diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index d9ae3c00..4dc8be82 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -3,7 +3,8 @@ name: Bug report
about: Create a report to help improve Tinyauth
title: "[BUG]"
labels: bug
-assignees: steveiliop56
+assignees:
+ - steveiliop56
---
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index b933db82..a4c9d6bd 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -3,7 +3,8 @@ name: Feature request
about: Suggest an idea for this project
title: "[FEATURE]"
labels: enhancement
-assignees: steveiliop56
+assignees:
+ - steveiliop56
---
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c8d7360f..12db1641 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,18 +5,21 @@ on:
- main
pull_request:
+permissions:
+ contents: read
+
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup bun
- uses: oven-sh/setup-bun@v2
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Setup go
- uses: actions/setup-go@v6
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: "^1.26.0"
@@ -50,6 +53,6 @@ jobs:
run: go test -coverprofile=coverage.txt -v ./...
- name: Upload coverage reports to Codecov
- uses: codecov/codecov-action@v6
+ uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 97738128..1656981b 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -4,12 +4,16 @@ on:
schedule:
- cron: "0 0 * * *"
+permissions:
+ contents: write
+ packages: write
+
jobs:
create-release:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Delete old release
run: gh release delete --cleanup-tag --yes nightly || echo release not found
@@ -19,7 +23,7 @@ jobs:
REPO: ${{ github.event.repository.name }}
- name: Create release
- uses: softprops/action-gh-release@v3
+ uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
with:
prerelease: true
tag_name: nightly
@@ -33,7 +37,7 @@ jobs:
BUILD_TIMESTAMP: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
@@ -51,15 +55,15 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
- name: Install bun
- uses: oven-sh/setup-bun@v2
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Install go
- uses: actions/setup-go@v6
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: "^1.26.0"
@@ -80,12 +84,12 @@ jobs:
- name: Build
run: |
cp -r frontend/dist internal/assets/dist
- go build -ldflags "-s -w -X github.com/steveiliop56/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
+ go build -ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
env:
CGO_ENABLED: 0
- name: Upload artifact
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tinyauth-amd64
path: tinyauth-amd64
@@ -97,15 +101,15 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
- name: Install bun
- uses: oven-sh/setup-bun@v2
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Install go
- uses: actions/setup-go@v6
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: "^1.26.0"
@@ -126,12 +130,12 @@ jobs:
- name: Build
run: |
cp -r frontend/dist internal/assets/dist
- go build -ldflags "-s -w -X github.com/steveiliop56/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
+ go build -ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
env:
CGO_ENABLED: 0
- name: Upload artifact
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tinyauth-arm64
path: tinyauth-arm64
@@ -143,28 +147,28 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/amd64
@@ -186,7 +190,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-linux-amd64
path: ${{ runner.temp }}/digests/*
@@ -201,28 +205,28 @@ jobs:
- image-build
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/amd64
@@ -245,7 +249,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-distroless-linux-amd64
path: ${{ runner.temp }}/digests/*
@@ -259,28 +263,28 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/arm64
@@ -302,7 +306,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-linux-arm64
path: ${{ runner.temp }}/digests/*
@@ -317,28 +321,28 @@ jobs:
- image-build-arm
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/arm64
@@ -361,7 +365,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-distroless-linux-arm64
path: ${{ runner.temp }}/digests/*
@@ -375,25 +379,25 @@ jobs:
- image-build-arm
steps:
- name: Download digests
- uses: actions/download-artifact@v8
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
flavor: |
@@ -414,25 +418,25 @@ jobs:
- image-build-arm-distroless
steps:
- name: Download digests
- uses: actions/download-artifact@v8
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-distroless-*
merge-multiple: true
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
flavor: |
@@ -452,14 +456,14 @@ jobs:
- binary-build
- binary-build-arm
steps:
- - uses: actions/download-artifact@v8
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: tinyauth-*
path: binaries
merge-multiple: true
- name: Release
- uses: softprops/action-gh-release@v3
+ uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
with:
files: binaries/*
tag_name: nightly
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 04ac2387..32e5de19 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -5,6 +5,10 @@ on:
tags:
- "v*"
+permissions:
+ contents: write
+ packages: write
+
jobs:
generate-metadata:
runs-on: ubuntu-latest
@@ -14,7 +18,7 @@ jobs:
BUILD_TIMESTAMP: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Generate metadata
id: metadata
@@ -29,13 +33,13 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install bun
- uses: oven-sh/setup-bun@v2
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Install go
- uses: actions/setup-go@v6
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: "^1.26.0"
@@ -56,12 +60,12 @@ jobs:
- name: Build
run: |
cp -r frontend/dist internal/assets/dist
- go build -ldflags "-s -w -X github.com/steveiliop56/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
+ go build -ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
env:
CGO_ENABLED: 0
- name: Upload artifact
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tinyauth-amd64
path: tinyauth-amd64
@@ -72,13 +76,13 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install bun
- uses: oven-sh/setup-bun@v2
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Install go
- uses: actions/setup-go@v6
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: "^1.26.0"
@@ -99,12 +103,12 @@ jobs:
- name: Build
run: |
cp -r frontend/dist internal/assets/dist
- go build -ldflags "-s -w -X github.com/steveiliop56/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
+ go build -ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
env:
CGO_ENABLED: 0
- name: Upload artifact
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tinyauth-arm64
path: tinyauth-arm64
@@ -115,26 +119,26 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/amd64
@@ -156,7 +160,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-linux-amd64
path: ${{ runner.temp }}/digests/*
@@ -170,26 +174,26 @@ jobs:
- image-build
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/amd64
@@ -212,7 +216,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-distroless-linux-amd64
path: ${{ runner.temp }}/digests/*
@@ -225,26 +229,26 @@ jobs:
- generate-metadata
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/arm64
@@ -266,7 +270,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-linux-arm64
path: ${{ runner.temp }}/digests/*
@@ -280,26 +284,26 @@ jobs:
- image-build-arm
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build and push
- uses: docker/build-push-action@v7
+ uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
id: build
with:
platforms: linux/arm64
@@ -322,7 +326,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- uses: actions/upload-artifact@v7
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-distroless-linux-arm64
path: ${{ runner.temp }}/digests/*
@@ -336,25 +340,25 @@ jobs:
- image-build-arm
steps:
- name: Download digests
- uses: actions/download-artifact@v8
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
flavor: |
@@ -377,25 +381,25 @@ jobs:
- image-build-arm-distroless
steps:
- name: Download digests
- uses: actions/download-artifact@v8
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-distroless-*
merge-multiple: true
- name: Login to GitHub Container Registry
- uses: docker/login-action@v4
+ uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v4
+ uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Docker meta
id: meta
- uses: docker/metadata-action@v6
+ uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
images: ghcr.io/${{ github.repository_owner }}/tinyauth
flavor: |
@@ -419,13 +423,13 @@ jobs:
- binary-build
- binary-build-arm
steps:
- - uses: actions/download-artifact@v8
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: tinyauth-*
path: binaries
merge-multiple: true
- name: Release
- uses: softprops/action-gh-release@v3
+ uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
with:
files: binaries/*
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
new file mode 100644
index 00000000..61a64a97
--- /dev/null
+++ b/.github/workflows/scorecard.yml
@@ -0,0 +1,43 @@
+name: Scorecard supply-chain security
+on:
+ branch_protection_rule:
+ schedule:
+ - cron: "31 17 * * 5"
+ push:
+ branches: ["main"]
+
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
+ permissions:
+ security-events: write
+ id-token: write
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
+ with:
+ persist-credentials: false
+
+ - name: Run analysis
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ publish_results: true
+
+ - name: Upload artifact
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ - name: Upload to code-scanning
+ uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
+ with:
+ sarif_file: results.sarif
diff --git a/.github/workflows/sponsors.yml b/.github/workflows/sponsors.yml
index 9f37794a..db9fc1d9 100644
--- a/.github/workflows/sponsors.yml
+++ b/.github/workflows/sponsors.yml
@@ -2,15 +2,19 @@ name: Generate Sponsors List
on:
workflow_dispatch:
+permissions:
+ contents: write
+ pull-requests: write
+
jobs:
generate-sponsors:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Generate Sponsors
- uses: JamesIves/github-sponsors-readme-action@v1
+ uses: JamesIves/github-sponsors-readme-action@2fd9142e765f755780202122261dc85e78459405 # v1
with:
token: ${{ secrets.SPONSORS_GENERATOR_PAT }}
active-only: false
@@ -18,7 +22,7 @@ jobs:
template: '
'
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v8
+ uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: |
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index f13e3a10..15f381ad 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -3,11 +3,15 @@ on:
schedule:
- cron: 0 10 * * *
+permissions:
+ issues: write
+ pull-requests: write
+
jobs:
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v10
+ - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
with:
days-before-stale: 30
stale-pr-message: This PR has been inactive for 30 days and will be marked as stale.
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 781201b7..00000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Connect to server",
- "type": "go",
- "request": "attach",
- "mode": "remote",
- "remotePath": "/tinyauth",
- "port": 4000,
- "host": "127.0.0.1",
- "debugAdapter": "legacy"
- }
- ]
-}
diff --git a/AI_POLICY.md b/AI_POLICY.md
new file mode 100644
index 00000000..7be9089b
--- /dev/null
+++ b/AI_POLICY.md
@@ -0,0 +1,27 @@
+# AI Usage Policy
+
+> [!NOTE]
+> By Tinyauth, we refer to the entire Tinyauth ([tinyauthapp](https://github.com/tinyauthapp)) organization and all of the repositories under it.
+
+## How we utilize AI in Tinyauth
+
+In Tinyauth, we see AI as another tool designed to help developers accelerate their work, ***not*** as something that should be doing the development for them. The ways we utilize large language models in Tinyauth are the following:
+
+- **Pull request reviews**: We utilize [CodeRabbit](https://www.coderabbit.ai/) for reviews in our pull requests which helps us find and fix issues faster, minimizing the time maintainers have to spend reviewing.
+- **Documentation and Issues**: We use [Dosu](https://dosu.dev/) to help resolve duplicate issues faster and automatically update our documentation based on changes in the code base.
+- **In-Line Suggestions**: GitHub's [Copilot](https://github.com/features/copilot) is partially used to fill in boilerplate code through in-line suggestions.
+
+## How we expect the community to use AI
+
+We expect the Tinyauth community to use AI as a tool for faster development and not as a way to implement entire features through prompts. For this reason, the following guidelines are in place for AI generated content:
+
+- **All usage must be clearly labeled**: Any content generated by AI must be clearly labeled as such. In the case that a pull request is clearly generated by AI and the author fails to disclose its use, it will be rejected.
+- **All generated content should be completely understood by the account holder**: The human who utilized the large language model to generate content must have a thorough understanding of it. This includes understanding the resulting output to the full extent and being able to explain it in detail in case it's needed.
+- **Automated systems are not allowed**: All forms of automated systems that utilize large language models to generate content without human oversight are forbidden. This includes any system that generates content without a human being directly involved in the process like for example with OpenClaw.
+- **No generated content other than text is allowed**: Images, videos, audio and any other form of content generated by AI other than text is not allowed in Tinyauth.
+- **AI pull requests are not guaranteed to be accepted or prioritized**: Any pull request that contains AI generated content is not guaranteed to be accepted and/or prioritized. The maintainers are responsible for reviewing all pull requests and determining whether or not they meet the standards of the project. AI generated content will be reviewed with the same standards as any other content, and may be rejected if it does not meet those standards.
+- **Large generated pull requests will be rejected**: Any pull request that contains a large amount of generated content will be rejected. This is because it is difficult for the maintainers to review and verify large amounts of generated content.
+
+## Tinyauth is developed by humans, for humans
+
+Please remember that Tinyauth is developed by humans. While AI can be a useful tool for **assisting** in the development process, it should not be used in place of the human brain. Moving forward, we are committed to ensuring that most, if not all the content in Tinyauth is created and reviewed by humans, and that AI is only used as a tool to assist in the development process.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 80239bde..2cbcc023 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,6 +2,9 @@
Contributing to Tinyauth is straightforward. Follow the steps below to set up a development server.
+> [!NOTE]
+> If you are using large language models to contribute to the project, please ensure that you have read and understood the [AI Policy](AI_POLICY.md).
+
## Requirements
- Bun
@@ -15,7 +18,7 @@ Contributing to Tinyauth is straightforward. Follow the steps below to set up a
Start by cloning the repository:
```sh
-git clone https://github.com/steveiliop56/tinyauth
+git clone https://github.com/tinyauthapp/tinyauth
cd tinyauth
```
diff --git a/Dockerfile b/Dockerfile
index f0ab9374..6b6cee1a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Site builder
-FROM oven/bun:1.3.12-alpine AS frontend-builder
+FROM oven/bun:1.3.13-alpine AS frontend-builder
WORKDIR /frontend
@@ -38,9 +38,9 @@ COPY ./internal ./internal
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
RUN CGO_ENABLED=0 go build -ldflags "-s -w \
- -X github.com/steveiliop56/tinyauth/internal/config.Version=${VERSION} \
- -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
- -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
+ -X github.com/tinyauthapp/tinyauth/internal/config.Version=${VERSION} \
+ -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
+ -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
# Runner
FROM alpine:3.23 AS runner
diff --git a/Dockerfile.distroless b/Dockerfile.distroless
index 98988fab..8626028c 100644
--- a/Dockerfile.distroless
+++ b/Dockerfile.distroless
@@ -1,5 +1,5 @@
# Site builder
-FROM oven/bun:1.3.12-alpine AS frontend-builder
+FROM oven/bun:1.3.13-alpine AS frontend-builder
WORKDIR /frontend
@@ -40,9 +40,9 @@ COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
RUN mkdir -p data
RUN CGO_ENABLED=0 go build -ldflags "-s -w \
- -X github.com/steveiliop56/tinyauth/internal/config.Version=${VERSION} \
- -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
- -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
+ -X github.com/tinyauthapp/tinyauth/internal/config.Version=${VERSION} \
+ -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
+ -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
# Runner
FROM gcr.io/distroless/static-debian12:latest AS runner
diff --git a/Makefile b/Makefile
index cecac215..7f4e393e 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ PROD_COMPOSE := $(shell test -f "docker-compose.test.prod.yml" && echo "docker-c
# Deps
deps:
- bun install --cwd frontend
+ bun install --frozen-lockfile --cwd frontend
go mod download
# Clean data
@@ -37,9 +37,9 @@ webui: clean-webui
# Build the binary
binary: webui
CGO_ENABLED=$(CGO_ENABLED) go build -ldflags "-s -w \
- -X github.com/steveiliop56/tinyauth/internal/config.Version=${TAG_NAME} \
- -X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
- -X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" \
+ -X github.com/tinyauthapp/tinyauth/internal/config.Version=${TAG_NAME} \
+ -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
+ -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" \
-o ${BIN_NAME} ./cmd/tinyauth
# Build for amd64
diff --git a/README.md b/README.md
index ad607f4b..beded4e1 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,15 @@
@@ -39,7 +43,7 @@ If you are still not sure if Tinyauth suits your needs you can try out the [demo
You can find documentation and guides on all of the available configuration of Tinyauth in the [website](https://tinyauth.app).
-If you wish to contribute to the documentation head over to the [repository](https://github.com/steveiliop56/tinyauth-docs).
+If you wish to contribute to the documentation head over to the [repository](https://github.com/tinyauthapp/docs).
## Discord
@@ -47,7 +51,7 @@ Tinyauth has a [Discord](https://discord.gg/eHzVaCzRRd) server. Feel free to hop
## Contributing
-All contributions to the codebase are welcome! If you have any free time, feel free to pick up an [issue](https://github.com/steveiliop56/tinyauth/issues) or add your own missing features. Make sure to check out the [contributing guide](./CONTRIBUTING.md) for instructions on how to get the development server up and running.
+All contributions to the codebase are welcome! If you have any free time, feel free to pick up an [issue](https://github.com/tinyauthapp/tinyauth/issues) or add your own missing features. Make sure to check out the [contributing guide](./CONTRIBUTING.md) for instructions on how to get the development server up and running.
## Localization
@@ -72,4 +76,4 @@ A big thank you to the following people for providing me with more coffee:
## Star History
-[](https://www.star-history.com/#steveiliop56/tinyauth&Date)
+[](https://www.star-history.com/#tinyauthapp/tinyauth&Date)
diff --git a/SECURITY.md b/SECURITY.md
index cf46677b..3665ec58 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,8 +2,8 @@
## Supported Versions
-It is recommended to use the [latest](https://github.com/steveiliop56/tinyauth/releases/latest) available version of tinyauth. This is because it includes security fixes, new features and dependency updates. Older versions, especially major ones, are not supported and won't receive security or patch updates.
+It is recommended to use the [latest](https://github.com/tinyauthapp/tinyauth/releases/latest) available version of tinyauth. This is because it includes security fixes, new features and dependency updates. Older versions, especially major ones, are not supported and won't receive security or patch updates.
## Reporting a Vulnerability
-Due to the nature of this app, it needs to be secure. If you discover any security issues or vulnerabilities in the app please contact me as soon as possible at . Please do not use the issues section to report security issues as I won't be able to patch them in time and they may get exploited by malicious actors.
+Due to the nature of this app, it needs to be secure. If you discover any security issues or vulnerabilities in the app please contact me as soon as possible at . Please do not use the issues section to report security issues as I won't be able to patch them in time and they may get exploited by malicious actors.
diff --git a/assets/discohook.json b/assets/discohook.json
index fb8c4cdd..725edfc0 100644
--- a/assets/discohook.json
+++ b/assets/discohook.json
@@ -3,7 +3,7 @@
"embeds": [
{
"title": "Welcome to Tinyauth Discord!",
- "description": "Tinyauth is a simple authentication middleware that adds a simple login screen or OAuth with Google, Github and any provider to all of your docker apps. It supports all the popular proxies like Traefik, Nginx and Caddy.\n\n**Information**\n\n• Github: \n• Website: ",
+ "description": "Tinyauth is a simple authentication middleware that adds a simple login screen or OAuth with Google, Github and any provider to all of your docker apps. It supports all the popular proxies like Traefik, Nginx and Caddy.\n\n**Information**\n\n• Github: \n• Website: ",
"url": "https://tinyauth.app",
"color": 7002085,
"author": {
@@ -14,9 +14,9 @@
},
"timestamp": "2025-06-06T12:25:27.629Z",
"thumbnail": {
- "url": "https://github.com/steveiliop56/tinyauth/blob/main/assets/logo.png?raw=true"
+ "url": "https://github.com/tinyauthapp/tinyauth/blob/main/assets/logo.png?raw=true"
}
}
],
"attachments": []
-}
\ No newline at end of file
+}
diff --git a/cmd/tinyauth/create_oidc_client.go b/cmd/tinyauth/create_oidc_client.go
index 75abe804..3a7cb1e2 100644
--- a/cmd/tinyauth/create_oidc_client.go
+++ b/cmd/tinyauth/create_oidc_client.go
@@ -7,7 +7,7 @@ import (
"strings"
"github.com/google/uuid"
- "github.com/steveiliop56/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/tinyauthapp/paerser/cli"
)
diff --git a/cmd/tinyauth/create_user.go b/cmd/tinyauth/create_user.go
index 2e6ce6ef..ef5fe266 100644
--- a/cmd/tinyauth/create_user.go
+++ b/cmd/tinyauth/create_user.go
@@ -6,7 +6,7 @@ import (
"strings"
"charm.land/huh/v2"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/tinyauthapp/paerser/cli"
"golang.org/x/crypto/bcrypt"
)
diff --git a/cmd/tinyauth/generate_totp.go b/cmd/tinyauth/generate_totp.go
index 8318f8de..22102c15 100644
--- a/cmd/tinyauth/generate_totp.go
+++ b/cmd/tinyauth/generate_totp.go
@@ -6,8 +6,8 @@ import (
"os"
"strings"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"charm.land/huh/v2"
"github.com/mdp/qrterminal/v3"
diff --git a/cmd/tinyauth/healthcheck.go b/cmd/tinyauth/healthcheck.go
index dc3df720..649a68c7 100644
--- a/cmd/tinyauth/healthcheck.go
+++ b/cmd/tinyauth/healthcheck.go
@@ -9,7 +9,7 @@ import (
"os"
"time"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/tinyauthapp/paerser/cli"
)
diff --git a/cmd/tinyauth/tinyauth.go b/cmd/tinyauth/tinyauth.go
index e0122f29..cc7c7261 100644
--- a/cmd/tinyauth/tinyauth.go
+++ b/cmd/tinyauth/tinyauth.go
@@ -4,10 +4,10 @@ import (
"fmt"
"charm.land/huh/v2"
- "github.com/steveiliop56/tinyauth/internal/bootstrap"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/loaders"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/bootstrap"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/loaders"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/rs/zerolog/log"
"github.com/tinyauthapp/paerser/cli"
diff --git a/cmd/tinyauth/verify_user.go b/cmd/tinyauth/verify_user.go
index 0f3ed5b1..5ab7aeee 100644
--- a/cmd/tinyauth/verify_user.go
+++ b/cmd/tinyauth/verify_user.go
@@ -4,8 +4,8 @@ import (
"errors"
"fmt"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"charm.land/huh/v2"
"github.com/pquerna/otp/totp"
diff --git a/cmd/tinyauth/version.go b/cmd/tinyauth/version.go
index d0e7709e..5bd2d9ac 100644
--- a/cmd/tinyauth/version.go
+++ b/cmd/tinyauth/version.go
@@ -3,7 +3,7 @@ package main
import (
"fmt"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/paerser/cli"
)
diff --git a/docker-compose.example.yml b/docker-compose.example.yml
index e33dc70e..6d816145 100644
--- a/docker-compose.example.yml
+++ b/docker-compose.example.yml
@@ -15,7 +15,7 @@ services:
traefik.http.routers.whoami.middlewares: tinyauth
tinyauth:
- image: ghcr.io/steveiliop56/tinyauth:v5
+ image: ghcr.io/tinyauthapp/tinyauth:v5
environment:
- TINYAUTH_APPURL=https://tinyauth.example.com
- TINYAUTH_AUTH_USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password
diff --git a/frontend/Dockerfile.dev b/frontend/Dockerfile.dev
index 0584f8c7..c86aaa3d 100644
--- a/frontend/Dockerfile.dev
+++ b/frontend/Dockerfile.dev
@@ -5,7 +5,7 @@ WORKDIR /frontend
COPY ./frontend/package.json ./
COPY ./frontend/bun.lock ./
-RUN bun install
+RUN bun install --frozen-lockfile
COPY ./frontend/public ./public
COPY ./frontend/src ./src
@@ -19,4 +19,4 @@ COPY ./frontend/vite.config.ts ./
EXPOSE 5173
-ENTRYPOINT ["bun", "run", "dev"]
\ No newline at end of file
+ENTRYPOINT ["bun", "run", "dev"]
diff --git a/frontend/src/components/auth/login-form.tsx b/frontend/src/components/auth/login-form.tsx
index 0255ed93..a0901a17 100644
--- a/frontend/src/components/auth/login-form.tsx
+++ b/frontend/src/components/auth/login-form.tsx
@@ -17,6 +17,7 @@ interface Props {
onSubmit: (data: LoginSchema) => void;
loading?: boolean;
formId?: string;
+ params?: string;
}
export const LoginForm = (props: Props) => {
@@ -71,6 +72,12 @@ export const LoginForm = (props: Props) => {
{
+ e.preventDefault();
+ window.location.replace(
+ `/forgot-password${props.params ? `${props.params}` : ""}`,
+ );
+ }}
className="text-muted-foreground hover:text-muted-foreground/80 text-sm absolute right-0 bottom-[2.565rem]" // 2.565 is *just* perfect
>
{t("forgotPasswordTitle")}
diff --git a/frontend/src/lib/i18n/locales/en-US.json b/frontend/src/lib/i18n/locales/en-US.json
index 5a9c9b08..0a5a76c8 100644
--- a/frontend/src/lib/i18n/locales/en-US.json
+++ b/frontend/src/lib/i18n/locales/en-US.json
@@ -79,5 +79,6 @@
"profileScopeName": "Profile",
"profileScopeDescription": "Allows the app to access your profile information.",
"groupsScopeName": "Groups",
- "groupsScopeDescription": "Allows the app to access your group information."
+ "groupsScopeDescription": "Allows the app to access your group information.",
+ "backToLoginButton": "Back to login"
}
diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json
index 5a9c9b08..dd39a6ce 100644
--- a/frontend/src/lib/i18n/locales/en.json
+++ b/frontend/src/lib/i18n/locales/en.json
@@ -79,5 +79,10 @@
"profileScopeName": "Profile",
"profileScopeDescription": "Allows the app to access your profile information.",
"groupsScopeName": "Groups",
- "groupsScopeDescription": "Allows the app to access your group information."
+ "groupsScopeDescription": "Allows the app to access your group information.",
+ "backToLoginButton": "Back to login",
+ "phoneScopeName": "Phone",
+ "phoneScopeDescription": "Allows the app to access your phone number.",
+ "addressScopeName": "Address",
+ "addressScopeDescription": "Allows the app to access your address."
}
diff --git a/frontend/src/pages/authorize-page.tsx b/frontend/src/pages/authorize-page.tsx
index 24357d22..f2b7c11d 100644
--- a/frontend/src/pages/authorize-page.tsx
+++ b/frontend/src/pages/authorize-page.tsx
@@ -17,7 +17,7 @@ import { toast } from "sonner";
import { useOIDCParams } from "@/lib/hooks/oidc";
import { useTranslation } from "react-i18next";
import { TFunction } from "i18next";
-import { Mail, Shield, User, Users } from "lucide-react";
+import { Mail, MapPin, Phone, Shield, User, Users } from "lucide-react";
import {
Tooltip,
TooltipContent,
@@ -61,6 +61,18 @@ const createScopeMap = (t: TFunction<"translation", undefined>): Scope[] => {
description: t("groupsScopeDescription"),
icon: ,
},
+ {
+ id: "phone",
+ name: t("phoneScopeName"),
+ description: t("phoneScopeDescription"),
+ icon: ,
+ },
+ {
+ id: "address",
+ name: t("addressScopeName"),
+ description: t("addressScopeDescription"),
+ icon: ,
+ },
];
};
diff --git a/frontend/src/pages/forgot-password-page.tsx b/frontend/src/pages/forgot-password-page.tsx
index 3b6c3a70..7d47d02f 100644
--- a/frontend/src/pages/forgot-password-page.tsx
+++ b/frontend/src/pages/forgot-password-page.tsx
@@ -10,12 +10,13 @@ import { Button } from "@/components/ui/button";
import { useAppContext } from "@/context/app-context";
import { useTranslation } from "react-i18next";
import Markdown from "react-markdown";
-import { useNavigate } from "react-router";
+import { useLocation } from "react-router";
export const ForgotPasswordPage = () => {
const { forgotPasswordMessage } = useAppContext();
const { t } = useTranslation();
- const navigate = useNavigate();
+ const { search } = useLocation();
+ const searchParams = new URLSearchParams(search);
return (
@@ -36,10 +37,13 @@ export const ForgotPasswordPage = () => {
className="w-full"
variant="outline"
onClick={() => {
- navigate("/login");
+ const eparams = searchParams.toString();
+ window.location.replace(
+ `/login${eparams.length > 0 ? `?${eparams}` : ""}`,
+ );
}}
>
- {t("notFoundButton")}
+ {t("backToLoginButton")}
diff --git a/frontend/src/pages/login-page.tsx b/frontend/src/pages/login-page.tsx
index ea7d716b..c39a0fb6 100644
--- a/frontend/src/pages/login-page.tsx
+++ b/frontend/src/pages/login-page.tsx
@@ -264,6 +264,10 @@ export const LoginPage = () => {
onSubmit={(values) => loginMutate(values)}
loading={loginIsPending || oauthIsPending}
formId={formId}
+ params={(() => {
+ const eparams = searchParams.toString();
+ return eparams.length > 0 ? `?${eparams}` : "";
+ })()}
/>
)}
{providers.length == 0 && (
diff --git a/gen/gen_env.go b/gen/gen_env.go
index d1a9b234..881888a9 100644
--- a/gen/gen_env.go
+++ b/gen/gen_env.go
@@ -10,7 +10,7 @@ import (
"reflect"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
)
type EnvEntry struct {
diff --git a/gen/gen_md.go b/gen/gen_md.go
index fa8025ed..ae8f0f19 100644
--- a/gen/gen_md.go
+++ b/gen/gen_md.go
@@ -10,7 +10,7 @@ import (
"reflect"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
)
type MarkdownEntry struct {
diff --git a/go.mod b/go.mod
index b8e439dd..0b7cfafa 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/steveiliop56/tinyauth
+module github.com/tinyauthapp/tinyauth
go 1.26.0
@@ -14,7 +14,7 @@ require (
github.com/google/uuid v1.6.0
github.com/mdp/qrterminal/v3 v3.2.1
github.com/pquerna/otp v1.5.0
- github.com/rs/zerolog v1.35.0
+ github.com/rs/zerolog v1.35.1
github.com/stretchr/testify v1.11.1
github.com/tinyauthapp/paerser v0.0.0-20260410140347-85c3740d6298
github.com/weppos/publicsuffix-go v0.50.3
@@ -22,7 +22,7 @@ require (
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
golang.org/x/oauth2 v0.36.0
gotest.tools/v3 v3.5.2
- modernc.org/sqlite v1.48.2
+ modernc.org/sqlite v1.49.1
)
require (
@@ -30,7 +30,7 @@ require (
charm.land/bubbletea/v2 v2.0.2 // indirect
charm.land/lipgloss/v2 v2.0.1 // indirect
dario.cat/mergo v1.0.1 // indirect
- github.com/Azure/go-ntlmssp v0.1.0 // indirect
+ github.com/Azure/go-ntlmssp v0.1.1 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
@@ -124,7 +124,7 @@ require (
golang.org/x/text v0.36.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- modernc.org/libc v1.70.0 // indirect
+ modernc.org/libc v1.72.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
rsc.io/qr v0.2.0 // indirect
diff --git a/go.sum b/go.sum
index ebe663a6..2e064d74 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,8 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A=
-github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
+github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDPw=
+github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
@@ -234,8 +234,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
-github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI=
-github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
+github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
+github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -329,10 +329,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
-modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
-modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
-modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=
-modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=
+modernc.org/cc/v4 v4.27.3 h1:uNCgn37E5U09mTv1XgskEVUJ8ADKpmFMPxzGJ0TSo+U=
+modernc.org/cc/v4 v4.27.3/go.mod h1:3YjcbCqhoTTHPycJDRl2WZKKFj0nwcOIPBfEZK0Hdk8=
+modernc.org/ccgo/v4 v4.32.4 h1:L5OB8rpEX4ZsXEQwGozRfJyJSFHbbNVOoQ59DU9/KuU=
+modernc.org/ccgo/v4 v4.32.4/go.mod h1:lY7f+fiTDHfcv6YlRgSkxYfhs+UvOEEzj49jAn2TOx0=
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
@@ -341,8 +341,8 @@ modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
-modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
-modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
+modernc.org/libc v1.72.0 h1:IEu559v9a0XWjw0DPoVKtXpO2qt5NVLAnFaBbjq+n8c=
+modernc.org/libc v1.72.0/go.mod h1:tTU8DL8A+XLVkEY3x5E/tO7s2Q/q42EtnNWda/L5QhQ=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -351,8 +351,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
-modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c=
-modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
+modernc.org/sqlite v1.49.1 h1:dYGHTKcX1sJ+EQDnUzvz4TJ5GbuvhNJa8Fg6ElGx73U=
+modernc.org/sqlite v1.49.1/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
diff --git a/internal/assets/migrations/000009_oidc_userinfo_profile.down.sql b/internal/assets/migrations/000009_oidc_userinfo_profile.down.sql
new file mode 100644
index 00000000..0baa9cfc
--- /dev/null
+++ b/internal/assets/migrations/000009_oidc_userinfo_profile.down.sql
@@ -0,0 +1,13 @@
+ALTER TABLE "oidc_userinfo" DROP COLUMN "given_name";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "family_name";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "middle_name";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "nickname";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "profile";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "picture";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "website";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "gender";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "birthdate";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "zoneinfo";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "locale";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "phone_number";
+ALTER TABLE "oidc_userinfo" DROP COLUMN "address";
diff --git a/internal/assets/migrations/000009_oidc_userinfo_profile.up.sql b/internal/assets/migrations/000009_oidc_userinfo_profile.up.sql
new file mode 100644
index 00000000..f91e964a
--- /dev/null
+++ b/internal/assets/migrations/000009_oidc_userinfo_profile.up.sql
@@ -0,0 +1,13 @@
+ALTER TABLE "oidc_userinfo" ADD COLUMN "given_name" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "family_name" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "middle_name" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "nickname" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "profile" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "picture" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "website" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "gender" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "birthdate" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "zoneinfo" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "locale" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "phone_number" TEXT NOT NULL DEFAULT "";
+ALTER TABLE "oidc_userinfo" ADD COLUMN "address" TEXT NOT NULL DEFAULT "{}";
diff --git a/internal/bootstrap/app_bootstrap.go b/internal/bootstrap/app_bootstrap.go
index 55c0f477..bc4d1894 100644
--- a/internal/bootstrap/app_bootstrap.go
+++ b/internal/bootstrap/app_bootstrap.go
@@ -12,11 +12,11 @@ import (
"strings"
"time"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
)
type BootstrapApp struct {
@@ -44,8 +44,6 @@ func NewBootstrapApp(config config.Config) *BootstrapApp {
}
func (app *BootstrapApp) Setup() error {
- fmt.Println("Tinyauth is moving to an organization! All versions after v5.0.7 will be released under ghcr.io/tinyauthapp/tinyauth. Existing images will continue to work but new features and updates (including security ones) will only be released under the new image path.")
-
// get app url
if app.config.AppURL == "" {
return fmt.Errorf("app URL cannot be empty, perhaps config loading failed")
@@ -65,7 +63,7 @@ func (app *BootstrapApp) Setup() error {
}
// Parse users
- users, err := utils.GetUsers(app.config.Auth.Users, app.config.Auth.UsersFile)
+ users, err := utils.GetUsers(app.config.Auth.Users, app.config.Auth.UsersFile, app.config.Auth.UserAttributes)
if err != nil {
return err
diff --git a/internal/bootstrap/db_bootstrap.go b/internal/bootstrap/db_bootstrap.go
index ab10daad..3f48f793 100644
--- a/internal/bootstrap/db_bootstrap.go
+++ b/internal/bootstrap/db_bootstrap.go
@@ -6,7 +6,7 @@ import (
"os"
"path/filepath"
- "github.com/steveiliop56/tinyauth/internal/assets"
+ "github.com/tinyauthapp/tinyauth/internal/assets"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
diff --git a/internal/bootstrap/router_bootstrap.go b/internal/bootstrap/router_bootstrap.go
index ef92d100..91d36ac2 100644
--- a/internal/bootstrap/router_bootstrap.go
+++ b/internal/bootstrap/router_bootstrap.go
@@ -4,9 +4,9 @@ import (
"fmt"
"slices"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/middleware"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/middleware"
"github.com/gin-gonic/gin"
)
diff --git a/internal/bootstrap/service_bootstrap.go b/internal/bootstrap/service_bootstrap.go
index a6d518e6..c2e03b74 100644
--- a/internal/bootstrap/service_bootstrap.go
+++ b/internal/bootstrap/service_bootstrap.go
@@ -1,9 +1,9 @@
package bootstrap
import (
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
)
type Services struct {
diff --git a/internal/config/config.go b/internal/config/config.go
index f9280f8e..3e05fff3 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -114,16 +114,44 @@ type ServerConfig struct {
}
type AuthConfig struct {
- IP IPConfig `description:"IP whitelisting config options." yaml:"ip"`
- Users []string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"`
- UsersFile string `description:"Path to the users file." yaml:"usersFile"`
- SubdomainsEnabled bool `description:"Enable subdomains support." yaml:"subdomainsEnabled"`
- SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"`
- SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"`
- SessionMaxLifetime int `description:"Maximum session lifetime in seconds." yaml:"sessionMaxLifetime"`
- LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"`
- LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"`
- TrustedProxies []string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
+ IP IPConfig `description:"IP whitelisting config options." yaml:"ip"`
+ Users []string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"`
+ SubdomainsEnabled bool `description:"Enable subdomains support." yaml:"subdomainsEnabled"`
+ UserAttributes map[string]UserAttributes `description:"Map of per-user OIDC attributes (username -> attributes)." yaml:"userAttributes"`
+ UsersFile string `description:"Path to the users file." yaml:"usersFile"`
+ SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"`
+ SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"`
+ SessionMaxLifetime int `description:"Maximum session lifetime in seconds." yaml:"sessionMaxLifetime"`
+ LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"`
+ LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"`
+ TrustedProxies []string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
+}
+
+type UserAttributes struct {
+ Name string `description:"Full name of the user." yaml:"name"`
+ GivenName string `description:"Given (first) name of the user." yaml:"givenName"`
+ FamilyName string `description:"Family (last) name of the user." yaml:"familyName"`
+ MiddleName string `description:"Middle name of the user." yaml:"middleName"`
+ Nickname string `description:"Nickname of the user." yaml:"nickname"`
+ Profile string `description:"URL of the user's profile page." yaml:"profile"`
+ Picture string `description:"URL of the user's profile picture." yaml:"picture"`
+ Website string `description:"URL of the user's website." yaml:"website"`
+ Email string `description:"Email address of the user." yaml:"email"`
+ Gender string `description:"Gender of the user." yaml:"gender"`
+ Birthdate string `description:"Birthdate of the user (YYYY-MM-DD)." yaml:"birthdate"`
+ Zoneinfo string `description:"Time zone of the user (e.g. Europe/Athens)." yaml:"zoneinfo"`
+ Locale string `description:"Locale of the user (e.g. en-US)." yaml:"locale"`
+ PhoneNumber string `description:"Phone number of the user." yaml:"phoneNumber"`
+ Address AddressClaim `description:"Address of the user." yaml:"address"`
+}
+
+type AddressClaim struct {
+ Formatted string `description:"Full mailing address, formatted for display." yaml:"formatted" json:"formatted,omitempty"`
+ StreetAddress string `description:"Street address." yaml:"streetAddress" json:"street_address,omitempty"`
+ Locality string `description:"City or locality." yaml:"locality" json:"locality,omitempty"`
+ Region string `description:"State, province, or region." yaml:"region" json:"region,omitempty"`
+ PostalCode string `description:"Zip or postal code." yaml:"postalCode" json:"postal_code,omitempty"`
+ Country string `description:"Country." yaml:"country" json:"country,omitempty"`
}
type IPConfig struct {
@@ -230,6 +258,7 @@ type User struct {
Username string
Password string
TotpSecret string
+ Attributes UserAttributes
}
type LdapUser struct {
@@ -256,6 +285,7 @@ type UserContext struct {
OAuthName string
OAuthSub string
LdapGroups string
+ Attributes UserAttributes
}
// API responses and queries
diff --git a/internal/controller/context_controller.go b/internal/controller/context_controller.go
index 8501bce1..da53303b 100644
--- a/internal/controller/context_controller.go
+++ b/internal/controller/context_controller.go
@@ -4,8 +4,8 @@ import (
"fmt"
"net/url"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
)
diff --git a/internal/controller/context_controller_test.go b/internal/controller/context_controller_test.go
index 3cff31c6..2329425b 100644
--- a/internal/controller/context_controller_test.go
+++ b/internal/controller/context_controller_test.go
@@ -7,10 +7,10 @@ import (
"testing"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
)
diff --git a/internal/controller/health_controller_test.go b/internal/controller/health_controller_test.go
index a12fd437..d1bed3b6 100644
--- a/internal/controller/health_controller_test.go
+++ b/internal/controller/health_controller_test.go
@@ -7,8 +7,8 @@ import (
"testing"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
)
diff --git a/internal/controller/oauth_controller.go b/internal/controller/oauth_controller.go
index f36e269d..614fa707 100644
--- a/internal/controller/oauth_controller.go
+++ b/internal/controller/oauth_controller.go
@@ -6,11 +6,11 @@ import (
"strings"
"time"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
diff --git a/internal/controller/oidc_controller.go b/internal/controller/oidc_controller.go
index 005b7c8e..fa614610 100644
--- a/internal/controller/oidc_controller.go
+++ b/internal/controller/oidc_controller.go
@@ -10,9 +10,9 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
)
type OIDCControllerConfig struct{}
diff --git a/internal/controller/oidc_controller_test.go b/internal/controller/oidc_controller_test.go
index 7f1dc1a4..a09697bf 100644
--- a/internal/controller/oidc_controller_test.go
+++ b/internal/controller/oidc_controller_test.go
@@ -12,12 +12,12 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
- "github.com/steveiliop56/tinyauth/internal/bootstrap"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/bootstrap"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go
index 9790daa9..724c6f6f 100644
--- a/internal/controller/proxy_controller.go
+++ b/internal/controller/proxy_controller.go
@@ -8,10 +8,10 @@ import (
"regexp"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go
index 5c07acf5..8ea81729 100644
--- a/internal/controller/proxy_controller_test.go
+++ b/internal/controller/proxy_controller_test.go
@@ -6,12 +6,12 @@ import (
"testing"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/bootstrap"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/bootstrap"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/internal/controller/resources_controller_test.go b/internal/controller/resources_controller_test.go
index 2b89aa10..a1996be3 100644
--- a/internal/controller/resources_controller_test.go
+++ b/internal/controller/resources_controller_test.go
@@ -7,8 +7,8 @@ import (
"testing"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/internal/controller/user_controller.go b/internal/controller/user_controller.go
index 161a520f..187b33b9 100644
--- a/internal/controller/user_controller.go
+++ b/internal/controller/user_controller.go
@@ -4,10 +4,11 @@ import (
"fmt"
"time"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp"
@@ -105,16 +106,32 @@ func (controller *UserController) loginHandler(c *gin.Context) {
controller.auth.RecordLoginAttempt(req.Username, true)
+ var localUser *config.User
if userSearch.Type == "local" {
user := controller.auth.GetLocalUser(userSearch.Username)
+ localUser = &user
+ }
+
+ if userSearch.Type == "local" && localUser != nil {
+ user := *localUser
if user.TotpSecret != "" {
tlog.App.Debug().Str("username", req.Username).Msg("User has TOTP enabled, requiring TOTP verification")
+ name := user.Attributes.Name
+ if name == "" {
+ name = utils.Capitalize(user.Username)
+ }
+
+ email := user.Attributes.Email
+ if email == "" {
+ email = utils.CompileUserEmail(user.Username, controller.config.CookieDomain)
+ }
+
err := controller.auth.CreateSessionCookie(c, &repository.Session{
Username: user.Username,
- Name: utils.Capitalize(user.Username),
- Email: utils.CompileUserEmail(user.Username, controller.config.CookieDomain),
+ Name: name,
+ Email: email,
Provider: "local",
TotpPending: true,
})
@@ -144,6 +161,15 @@ func (controller *UserController) loginHandler(c *gin.Context) {
Provider: "local",
}
+ if userSearch.Type == "local" && localUser != nil {
+ if localUser.Attributes.Name != "" {
+ sessionCookie.Name = localUser.Attributes.Name
+ }
+ if localUser.Attributes.Email != "" {
+ sessionCookie.Email = localUser.Attributes.Email
+ }
+ }
+
if userSearch.Type == "ldap" {
sessionCookie.Provider = "ldap"
}
@@ -258,6 +284,13 @@ func (controller *UserController) totpHandler(c *gin.Context) {
Provider: "local",
}
+ if user.Attributes.Name != "" {
+ sessionCookie.Name = user.Attributes.Name
+ }
+ if user.Attributes.Email != "" {
+ sessionCookie.Email = user.Attributes.Email
+ }
+
tlog.App.Trace().Interface("session_cookie", sessionCookie).Msg("Creating session cookie")
err = controller.auth.CreateSessionCookie(c, &sessionCookie)
diff --git a/internal/controller/user_controller_test.go b/internal/controller/user_controller_test.go
index d69f9304..d7a07732 100644
--- a/internal/controller/user_controller_test.go
+++ b/internal/controller/user_controller_test.go
@@ -4,19 +4,18 @@ import (
"encoding/json"
"net/http/httptest"
"path"
- "slices"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp"
- "github.com/steveiliop56/tinyauth/internal/bootstrap"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/bootstrap"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -36,6 +35,23 @@ func TestUserController(t *testing.T) {
Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
TotpSecret: "JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK",
},
+ {
+ Username: "attruser",
+ Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
+ Attributes: config.UserAttributes{
+ Name: "Alice Smith",
+ Email: "alice@example.com",
+ },
+ },
+ {
+ Username: "attrtotpuser",
+ Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
+ TotpSecret: "JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK",
+ Attributes: config.UserAttributes{
+ Name: "Bob Jones",
+ Email: "bob@example.com",
+ },
+ },
},
SessionExpiry: 10, // 10 seconds, useful for testing
CookieDomain: "example.com",
@@ -273,6 +289,64 @@ func TestUserController(t *testing.T) {
assert.Contains(t, recorder.Body.String(), "Too many failed TOTP attempts.")
},
},
+ {
+ description: "Login uses name and email from user attributes",
+ middlewares: []gin.HandlerFunc{},
+ run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
+ loginReq := controller.LoginRequest{Username: "attruser", Password: "password"}
+ body, err := json.Marshal(loginReq)
+ require.NoError(t, err)
+
+ req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(body)))
+ req.Header.Set("Content-Type", "application/json")
+ router.ServeHTTP(recorder, req)
+
+ require.Equal(t, 200, recorder.Code)
+ cookies := recorder.Result().Cookies()
+ require.Len(t, cookies, 1)
+ assert.Equal(t, "tinyauth-session", cookies[0].Name)
+ },
+ },
+ {
+ description: "Login with TOTP uses name and email from user attributes in pending session",
+ middlewares: []gin.HandlerFunc{},
+ run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
+ loginReq := controller.LoginRequest{Username: "attrtotpuser", Password: "password"}
+ body, err := json.Marshal(loginReq)
+ require.NoError(t, err)
+
+ req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(body)))
+ req.Header.Set("Content-Type", "application/json")
+ router.ServeHTTP(recorder, req)
+
+ require.Equal(t, 200, recorder.Code)
+ var res map[string]any
+ require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &res))
+ assert.Equal(t, true, res["totpPending"])
+ require.Len(t, recorder.Result().Cookies(), 1)
+ },
+ },
+ {
+ description: "TOTP completion uses name and email from user attributes",
+ middlewares: []gin.HandlerFunc{},
+ run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
+ code, err := totp.GenerateCode("JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK", time.Now())
+ require.NoError(t, err)
+
+ totpReq := controller.TotpRequest{Code: code}
+ body, err := json.Marshal(totpReq)
+ require.NoError(t, err)
+
+ req := httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(body)))
+ req.Header.Set("Content-Type", "application/json")
+ router.ServeHTTP(recorder, req)
+
+ require.Equal(t, 200, recorder.Code)
+ cookies := recorder.Result().Cookies()
+ require.Len(t, cookies, 1)
+ assert.Equal(t, "tinyauth-session", cookies[0].Name)
+ },
+ },
}
oauthBrokerCfgs := make(map[string]config.OAuthServiceConfig)
@@ -305,9 +379,31 @@ func TestUserController(t *testing.T) {
authService.ClearRateLimitsTestingOnly()
}
- setTotpMiddlewareOverrides := []string{
- "Should be able to login with totp",
- "Totp should rate limit on multiple invalid attempts",
+ setTotpMiddlewareOverrides := map[string]config.UserContext{
+ "Should be able to login with totp": {
+ Username: "totpuser",
+ Name: "Totpuser",
+ Email: "totpuser@example.com",
+ Provider: "local",
+ TotpPending: true,
+ TotpEnabled: true,
+ },
+ "Totp should rate limit on multiple invalid attempts": {
+ Username: "totpuser",
+ Name: "Totpuser",
+ Email: "totpuser@example.com",
+ Provider: "local",
+ TotpPending: true,
+ TotpEnabled: true,
+ },
+ "TOTP completion uses name and email from user attributes": {
+ Username: "attrtotpuser",
+ Name: "Bob Jones",
+ Email: "bob@example.com",
+ Provider: "local",
+ TotpPending: true,
+ TotpEnabled: true,
+ },
}
for _, test := range tests {
@@ -321,18 +417,10 @@ func TestUserController(t *testing.T) {
// Gin is stupid and doesn't allow setting a middleware after the groups
// so we need to do some stupid overrides here
- if slices.Contains(setTotpMiddlewareOverrides, test.description) {
- // Assuming the cookie is set, it should be picked up by the
- // context middleware
+ if ctx, ok := setTotpMiddlewareOverrides[test.description]; ok {
+ ctx := ctx
router.Use(func(c *gin.Context) {
- c.Set("context", &config.UserContext{
- Username: "totpuser",
- Name: "Totpuser",
- Email: "totpuser@example.com",
- Provider: "local",
- TotpPending: true,
- TotpEnabled: true,
- })
+ c.Set("context", &ctx)
})
}
diff --git a/internal/controller/well_known_controller.go b/internal/controller/well_known_controller.go
index d09de0f5..f31a9ed7 100644
--- a/internal/controller/well_known_controller.go
+++ b/internal/controller/well_known_controller.go
@@ -5,7 +5,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/service"
)
type OpenIDConnectConfiguration struct {
@@ -61,7 +61,7 @@ func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context
SubjectTypesSupported: []string{"pairwise"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post"},
- ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "email_verified", "groups"},
+ ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "email_verified", "groups", "phone_number", "phone_number_verified", "address", "given_name", "family_name", "middle_name", "nickname", "profile", "picture", "website", "gender", "birthdate", "zoneinfo", "locale"},
ServiceDocumentation: "https://tinyauth.app/docs/guides/oidc",
RequestParameterSupported: true,
RequestObjectSigningAlgValuesSupported: []string{"none"},
diff --git a/internal/controller/well_known_controller_test.go b/internal/controller/well_known_controller_test.go
index 47a0e7ef..7d8d05f5 100644
--- a/internal/controller/well_known_controller_test.go
+++ b/internal/controller/well_known_controller_test.go
@@ -8,12 +8,12 @@ import (
"testing"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/bootstrap"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/controller"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/bootstrap"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/controller"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -67,7 +67,7 @@ func TestWellKnownController(t *testing.T) {
SubjectTypesSupported: []string{"pairwise"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post"},
- ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "email_verified", "groups"},
+ ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "email_verified", "groups", "phone_number", "phone_number_verified", "address", "given_name", "family_name", "middle_name", "nickname", "profile", "picture", "website", "gender", "birthdate", "zoneinfo", "locale"},
ServiceDocumentation: "https://tinyauth.app/docs/guides/oidc",
RequestParameterSupported: true,
RequestObjectSigningAlgValuesSupported: []string{"none"},
diff --git a/internal/middleware/context_middleware.go b/internal/middleware/context_middleware.go
index 025c64ec..651d9d85 100644
--- a/internal/middleware/context_middleware.go
+++ b/internal/middleware/context_middleware.go
@@ -4,10 +4,10 @@ import (
"strings"
"time"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/service"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
)
@@ -99,6 +99,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
}
var ldapGroups []string
+ var localAttributes config.UserAttributes
if cookie.Provider == "ldap" {
ldapUser, err := m.auth.GetLdapUser(userSearch.Username)
@@ -112,6 +113,11 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
ldapGroups = ldapUser.Groups
}
+ if cookie.Provider == "local" {
+ localUser := m.auth.GetLocalUser(cookie.Username)
+ localAttributes = localUser.Attributes
+ }
+
m.auth.RefreshSessionCookie(c)
c.Set("context", &config.UserContext{
Username: cookie.Username,
@@ -120,6 +126,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
Provider: cookie.Provider,
IsLoggedIn: true,
LdapGroups: strings.Join(ldapGroups, ","),
+ Attributes: localAttributes,
})
c.Next()
return
@@ -202,13 +209,23 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
return
}
+ name := utils.Capitalize(user.Username)
+ if user.Attributes.Name != "" {
+ name = user.Attributes.Name
+ }
+ email := utils.CompileUserEmail(user.Username, m.config.CookieDomain)
+ if user.Attributes.Email != "" {
+ email = user.Attributes.Email
+ }
+
c.Set("context", &config.UserContext{
Username: user.Username,
- Name: utils.Capitalize(user.Username),
- Email: utils.CompileUserEmail(user.Username, m.config.CookieDomain),
+ Name: name,
+ Email: email,
Provider: "local",
IsLoggedIn: true,
IsBasicAuth: true,
+ Attributes: user.Attributes,
})
c.Next()
return
diff --git a/internal/middleware/ui_middleware.go b/internal/middleware/ui_middleware.go
index c150c210..96553b07 100644
--- a/internal/middleware/ui_middleware.go
+++ b/internal/middleware/ui_middleware.go
@@ -8,8 +8,8 @@ import (
"strings"
"time"
- "github.com/steveiliop56/tinyauth/internal/assets"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/assets"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
)
diff --git a/internal/middleware/zerolog_middleware.go b/internal/middleware/zerolog_middleware.go
index 635d74d5..d75e3a72 100644
--- a/internal/middleware/zerolog_middleware.go
+++ b/internal/middleware/zerolog_middleware.go
@@ -5,7 +5,7 @@ import (
"time"
"github.com/gin-gonic/gin"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
)
// See context middleware for explanation of why we have to do this
diff --git a/internal/repository/models.go b/internal/repository/models.go
index f08dd512..bc2e2c66 100644
--- a/internal/repository/models.go
+++ b/internal/repository/models.go
@@ -34,6 +34,19 @@ type OidcUserinfo struct {
Email string
Groups string
UpdatedAt int64
+ GivenName string
+ FamilyName string
+ MiddleName string
+ Nickname string
+ Profile string
+ Picture string
+ Website string
+ Gender string
+ Birthdate string
+ Zoneinfo string
+ Locale string
+ PhoneNumber string
+ Address string
}
type Session struct {
diff --git a/internal/repository/oidc_queries.sql.go b/internal/repository/oidc_queries.sql.go
index 8ca6893b..7caac9d4 100644
--- a/internal/repository/oidc_queries.sql.go
+++ b/internal/repository/oidc_queries.sql.go
@@ -124,11 +124,24 @@ INSERT INTO "oidc_userinfo" (
"preferred_username",
"email",
"groups",
- "updated_at"
+ "updated_at",
+ "given_name",
+ "family_name",
+ "middle_name",
+ "nickname",
+ "profile",
+ "picture",
+ "website",
+ "gender",
+ "birthdate",
+ "zoneinfo",
+ "locale",
+ "phone_number",
+ "address"
) VALUES (
- ?, ?, ?, ?, ?, ?
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
-RETURNING sub, name, preferred_username, email, "groups", updated_at
+RETURNING sub, name, preferred_username, email, "groups", updated_at, given_name, family_name, middle_name, nickname, profile, picture, website, gender, birthdate, zoneinfo, locale, phone_number, address
`
type CreateOidcUserInfoParams struct {
@@ -138,6 +151,19 @@ type CreateOidcUserInfoParams struct {
Email string
Groups string
UpdatedAt int64
+ GivenName string
+ FamilyName string
+ MiddleName string
+ Nickname string
+ Profile string
+ Picture string
+ Website string
+ Gender string
+ Birthdate string
+ Zoneinfo string
+ Locale string
+ PhoneNumber string
+ Address string
}
func (q *Queries) CreateOidcUserInfo(ctx context.Context, arg CreateOidcUserInfoParams) (OidcUserinfo, error) {
@@ -148,6 +174,19 @@ func (q *Queries) CreateOidcUserInfo(ctx context.Context, arg CreateOidcUserInfo
arg.Email,
arg.Groups,
arg.UpdatedAt,
+ arg.GivenName,
+ arg.FamilyName,
+ arg.MiddleName,
+ arg.Nickname,
+ arg.Profile,
+ arg.Picture,
+ arg.Website,
+ arg.Gender,
+ arg.Birthdate,
+ arg.Zoneinfo,
+ arg.Locale,
+ arg.PhoneNumber,
+ arg.Address,
)
var i OidcUserinfo
err := row.Scan(
@@ -157,6 +196,19 @@ func (q *Queries) CreateOidcUserInfo(ctx context.Context, arg CreateOidcUserInfo
&i.Email,
&i.Groups,
&i.UpdatedAt,
+ &i.GivenName,
+ &i.FamilyName,
+ &i.MiddleName,
+ &i.Nickname,
+ &i.Profile,
+ &i.Picture,
+ &i.Website,
+ &i.Gender,
+ &i.Birthdate,
+ &i.Zoneinfo,
+ &i.Locale,
+ &i.PhoneNumber,
+ &i.Address,
)
return i, err
}
@@ -456,7 +508,7 @@ func (q *Queries) GetOidcTokenBySub(ctx context.Context, sub string) (OidcToken,
}
const getOidcUserInfo = `-- name: GetOidcUserInfo :one
-SELECT sub, name, preferred_username, email, "groups", updated_at FROM "oidc_userinfo"
+SELECT sub, name, preferred_username, email, "groups", updated_at, given_name, family_name, middle_name, nickname, profile, picture, website, gender, birthdate, zoneinfo, locale, phone_number, address FROM "oidc_userinfo"
WHERE "sub" = ?
`
@@ -470,6 +522,19 @@ func (q *Queries) GetOidcUserInfo(ctx context.Context, sub string) (OidcUserinfo
&i.Email,
&i.Groups,
&i.UpdatedAt,
+ &i.GivenName,
+ &i.FamilyName,
+ &i.MiddleName,
+ &i.Nickname,
+ &i.Profile,
+ &i.Picture,
+ &i.Website,
+ &i.Gender,
+ &i.Birthdate,
+ &i.Zoneinfo,
+ &i.Locale,
+ &i.PhoneNumber,
+ &i.Address,
)
return i, err
}
diff --git a/internal/service/access_controls_service.go b/internal/service/access_controls_service.go
index 087ce883..56849de4 100644
--- a/internal/service/access_controls_service.go
+++ b/internal/service/access_controls_service.go
@@ -4,8 +4,8 @@ import (
"errors"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
)
type AccessControlsService struct {
diff --git a/internal/service/auth_service.go b/internal/service/auth_service.go
index 46758572..3b00e282 100644
--- a/internal/service/auth_service.go
+++ b/internal/service/auth_service.go
@@ -10,10 +10,10 @@ import (
"sync"
"time"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
diff --git a/internal/service/docker_service.go b/internal/service/docker_service.go
index fc96fb9d..97179242 100644
--- a/internal/service/docker_service.go
+++ b/internal/service/docker_service.go
@@ -4,9 +4,9 @@ import (
"context"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/decoders"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/decoders"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
container "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
diff --git a/internal/service/ldap_service.go b/internal/service/ldap_service.go
index c48127aa..0963ebf5 100644
--- a/internal/service/ldap_service.go
+++ b/internal/service/ldap_service.go
@@ -9,7 +9,7 @@ import (
"github.com/cenkalti/backoff/v5"
ldapgo "github.com/go-ldap/ldap/v3"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
)
type LdapServiceConfig struct {
diff --git a/internal/service/oauth_broker_service.go b/internal/service/oauth_broker_service.go
index 2f947138..e67fc11c 100644
--- a/internal/service/oauth_broker_service.go
+++ b/internal/service/oauth_broker_service.go
@@ -1,8 +1,8 @@
package service
import (
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"golang.org/x/exp/slices"
"golang.org/x/oauth2"
diff --git a/internal/service/oauth_extractors.go b/internal/service/oauth_extractors.go
index 91b13877..45d03f74 100644
--- a/internal/service/oauth_extractors.go
+++ b/internal/service/oauth_extractors.go
@@ -8,7 +8,7 @@ import (
"net/http"
"strconv"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
)
type GithubEmailResponse []struct {
diff --git a/internal/service/oauth_presets.go b/internal/service/oauth_presets.go
index 477ea0e5..df23be5e 100644
--- a/internal/service/oauth_presets.go
+++ b/internal/service/oauth_presets.go
@@ -1,7 +1,7 @@
package service
import (
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
"golang.org/x/oauth2/endpoints"
)
diff --git a/internal/service/oauth_service.go b/internal/service/oauth_service.go
index 1e6cd51e..4ef118ea 100644
--- a/internal/service/oauth_service.go
+++ b/internal/service/oauth_service.go
@@ -6,7 +6,7 @@ import (
"net/http"
"time"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
"golang.org/x/oauth2"
)
diff --git a/internal/service/oidc_service.go b/internal/service/oidc_service.go
index 299749aa..888ad0e9 100644
--- a/internal/service/oidc_service.go
+++ b/internal/service/oidc_service.go
@@ -20,15 +20,15 @@ import (
"github.com/gin-gonic/gin"
"github.com/go-jose/go-jose/v4"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/repository"
- "github.com/steveiliop56/tinyauth/internal/utils"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"golang.org/x/exp/slices"
)
var (
- SupportedScopes = []string{"openid", "profile", "email", "groups"}
+ SupportedScopes = []string{"openid", "profile", "email", "phone", "address", "groups"}
SupportedResponseTypes = []string{"code"}
SupportedGrantTypes = []string{"authorization_code", "refresh_token"}
)
@@ -48,6 +48,17 @@ type ClaimSet struct {
Iat int64 `json:"iat"`
Exp int64 `json:"exp"`
Name string `json:"name,omitempty"`
+ GivenName string `json:"given_name,omitempty"`
+ FamilyName string `json:"family_name,omitempty"`
+ MiddleName string `json:"middle_name,omitempty"`
+ Nickname string `json:"nickname,omitempty"`
+ Profile string `json:"profile,omitempty"`
+ Picture string `json:"picture,omitempty"`
+ Website string `json:"website,omitempty"`
+ Gender string `json:"gender,omitempty"`
+ Birthdate string `json:"birthdate,omitempty"`
+ Zoneinfo string `json:"zoneinfo,omitempty"`
+ Locale string `json:"locale,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty"`
@@ -56,13 +67,27 @@ type ClaimSet struct {
}
type UserinfoResponse struct {
- Sub string `json:"sub"`
- Name string `json:"name,omitempty"`
- Email string `json:"email,omitempty"`
- PreferredUsername string `json:"preferred_username,omitempty"`
- Groups []string `json:"groups,omitempty"`
- EmailVerified bool `json:"email_verified,omitempty"`
- UpdatedAt int64 `json:"updated_at"`
+ Sub string `json:"sub"`
+ Name string `json:"name,omitempty"`
+ GivenName string `json:"given_name,omitempty"`
+ FamilyName string `json:"family_name,omitempty"`
+ MiddleName string `json:"middle_name,omitempty"`
+ Nickname string `json:"nickname,omitempty"`
+ Profile string `json:"profile,omitempty"`
+ Picture string `json:"picture,omitempty"`
+ Website string `json:"website,omitempty"`
+ Gender string `json:"gender,omitempty"`
+ Birthdate string `json:"birthdate,omitempty"`
+ Zoneinfo string `json:"zoneinfo,omitempty"`
+ Locale string `json:"locale,omitempty"`
+ Email string `json:"email,omitempty"`
+ PreferredUsername string `json:"preferred_username,omitempty"`
+ Groups []string `json:"groups,omitempty"`
+ EmailVerified bool `json:"email_verified,omitempty"`
+ PhoneNumber string `json:"phone_number,omitempty"`
+ PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
+ Address *config.AddressClaim `json:"address,omitempty"`
+ UpdatedAt int64 `json:"updated_at"`
}
type TokenResponse struct {
@@ -342,12 +367,30 @@ func (service *OIDCService) StoreCode(c *gin.Context, sub string, code string, r
}
func (service *OIDCService) StoreUserinfo(c *gin.Context, sub string, userContext config.UserContext, req AuthorizeRequest) error {
+ addressJSON, err := json.Marshal(userContext.Attributes.Address)
+ if err != nil {
+ return err
+ }
+
userInfoParams := repository.CreateOidcUserInfoParams{
Sub: sub,
Name: userContext.Name,
Email: userContext.Email,
PreferredUsername: userContext.Username,
UpdatedAt: time.Now().Unix(),
+ GivenName: userContext.Attributes.GivenName,
+ FamilyName: userContext.Attributes.FamilyName,
+ MiddleName: userContext.Attributes.MiddleName,
+ Nickname: userContext.Attributes.Nickname,
+ Profile: userContext.Attributes.Profile,
+ Picture: userContext.Attributes.Picture,
+ Website: userContext.Attributes.Website,
+ Gender: userContext.Attributes.Gender,
+ Birthdate: userContext.Attributes.Birthdate,
+ Zoneinfo: userContext.Attributes.Zoneinfo,
+ Locale: userContext.Attributes.Locale,
+ PhoneNumber: userContext.Attributes.PhoneNumber,
+ Address: string(addressJSON),
}
// Tinyauth will pass through the groups it got from an LDAP or an OIDC server
@@ -359,7 +402,7 @@ func (service *OIDCService) StoreUserinfo(c *gin.Context, sub string, userContex
userInfoParams.Groups = userContext.OAuthGroups
}
- _, err := service.queries.CreateOidcUserInfo(c, userInfoParams)
+ _, err = service.queries.CreateOidcUserInfo(c, userInfoParams)
return err
}
@@ -637,12 +680,22 @@ func (service *OIDCService) CompileUserinfo(user repository.OidcUserinfo, scope
if slices.Contains(scopes, "profile") {
userInfo.Name = user.Name
userInfo.PreferredUsername = user.PreferredUsername
+ userInfo.GivenName = user.GivenName
+ userInfo.FamilyName = user.FamilyName
+ userInfo.MiddleName = user.MiddleName
+ userInfo.Nickname = user.Nickname
+ userInfo.Profile = user.Profile
+ userInfo.Picture = user.Picture
+ userInfo.Website = user.Website
+ userInfo.Gender = user.Gender
+ userInfo.Birthdate = user.Birthdate
+ userInfo.Zoneinfo = user.Zoneinfo
+ userInfo.Locale = user.Locale
}
if slices.Contains(scopes, "email") {
userInfo.Email = user.Email
- // We can set this as a configuration option in the future but for now it's a good idea to assume it's true
- userInfo.EmailVerified = true
+ userInfo.EmailVerified = user.Email != ""
}
if slices.Contains(scopes, "groups") {
@@ -653,6 +706,19 @@ func (service *OIDCService) CompileUserinfo(user repository.OidcUserinfo, scope
}
}
+ if slices.Contains(scopes, "phone") {
+ userInfo.PhoneNumber = user.PhoneNumber
+ verified := user.PhoneNumber != ""
+ userInfo.PhoneNumberVerified = &verified
+ }
+
+ if slices.Contains(scopes, "address") {
+ var addr config.AddressClaim
+ if err := json.Unmarshal([]byte(user.Address), &addr); err == nil {
+ userInfo.Address = &addr
+ }
+ }
+
return userInfo
}
diff --git a/internal/service/oidc_service_test.go b/internal/service/oidc_service_test.go
new file mode 100644
index 00000000..222ad626
--- /dev/null
+++ b/internal/service/oidc_service_test.go
@@ -0,0 +1,198 @@
+package service_test
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/repository"
+ "github.com/tinyauthapp/tinyauth/internal/service"
+)
+
+func newTestUser() repository.OidcUserinfo {
+ addr := config.AddressClaim{
+ Formatted: "123 Main St",
+ StreetAddress: "123 Main St",
+ Locality: "Springfield",
+ Region: "IL",
+ PostalCode: "62701",
+ Country: "US",
+ }
+ addrJSON, _ := json.Marshal(addr)
+
+ return repository.OidcUserinfo{
+ Sub: "test-sub",
+ Name: "Test User",
+ PreferredUsername: "testuser",
+ Email: "test@example.com",
+ Groups: "admins,users",
+ UpdatedAt: 1234567890,
+ GivenName: "Test",
+ FamilyName: "User",
+ MiddleName: "M",
+ Nickname: "testy",
+ Profile: "https://example.com/testuser",
+ Picture: "https://example.com/testuser.jpg",
+ Website: "https://testuser.example.com",
+ Gender: "male",
+ Birthdate: "1990-01-01",
+ Zoneinfo: "America/Chicago",
+ Locale: "en-US",
+ PhoneNumber: "+15555550100",
+ Address: string(addrJSON),
+ }
+}
+
+func TestCompileUserinfo(t *testing.T) {
+ dir := t.TempDir()
+ svc := service.NewOIDCService(service.OIDCServiceConfig{
+ PrivateKeyPath: dir + "/key.pem",
+ PublicKeyPath: dir + "/key.pub",
+ Issuer: "https://tinyauth.example.com",
+ SessionExpiry: 3600,
+ }, nil)
+ require.NoError(t, svc.Init())
+
+ type testCase struct {
+ description string
+ mutate func(u *repository.OidcUserinfo)
+ scope string
+ run func(t *testing.T, info service.UserinfoResponse)
+ }
+
+ tests := []testCase{
+ {
+ description: "openid scope only returns sub and updated_at",
+ scope: "openid",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, "test-sub", info.Sub)
+ assert.Equal(t, int64(1234567890), info.UpdatedAt)
+ assert.Empty(t, info.Name)
+ assert.Empty(t, info.Email)
+ assert.Nil(t, info.Groups)
+ assert.Nil(t, info.PhoneNumberVerified)
+ assert.Nil(t, info.Address)
+ },
+ },
+ {
+ description: "profile scope returns all profile fields",
+ scope: "openid,profile",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, "Test User", info.Name)
+ assert.Equal(t, "testuser", info.PreferredUsername)
+ assert.Equal(t, "Test", info.GivenName)
+ assert.Equal(t, "User", info.FamilyName)
+ assert.Equal(t, "M", info.MiddleName)
+ assert.Equal(t, "testy", info.Nickname)
+ assert.Equal(t, "https://example.com/testuser", info.Profile)
+ assert.Equal(t, "https://example.com/testuser.jpg", info.Picture)
+ assert.Equal(t, "https://testuser.example.com", info.Website)
+ assert.Equal(t, "male", info.Gender)
+ assert.Equal(t, "1990-01-01", info.Birthdate)
+ assert.Equal(t, "America/Chicago", info.Zoneinfo)
+ assert.Equal(t, "en-US", info.Locale)
+ assert.Empty(t, info.Email)
+ },
+ },
+ {
+ description: "email scope sets email and email_verified true when email present",
+ scope: "openid,email",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, "test@example.com", info.Email)
+ assert.True(t, info.EmailVerified)
+ assert.Empty(t, info.Name)
+ },
+ },
+ {
+ description: "email scope sets email_verified false when email absent",
+ scope: "openid,email",
+ mutate: func(u *repository.OidcUserinfo) { u.Email = "" },
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Empty(t, info.Email)
+ assert.False(t, info.EmailVerified)
+ },
+ },
+ {
+ description: "phone scope sets phone_number_verified true when phone present",
+ scope: "openid,phone",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, "+15555550100", info.PhoneNumber)
+ require.NotNil(t, info.PhoneNumberVerified)
+ assert.True(t, *info.PhoneNumberVerified)
+ },
+ },
+ {
+ description: "phone scope sets phone_number_verified false when phone absent",
+ scope: "openid,phone",
+ mutate: func(u *repository.OidcUserinfo) { u.PhoneNumber = "" },
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ require.NotNil(t, info.PhoneNumberVerified)
+ assert.False(t, *info.PhoneNumberVerified)
+ },
+ },
+ {
+ description: "address scope returns parsed address",
+ scope: "openid,address",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ require.NotNil(t, info.Address)
+ assert.Equal(t, "123 Main St", info.Address.Formatted)
+ assert.Equal(t, "123 Main St", info.Address.StreetAddress)
+ assert.Equal(t, "Springfield", info.Address.Locality)
+ assert.Equal(t, "IL", info.Address.Region)
+ assert.Equal(t, "62701", info.Address.PostalCode)
+ assert.Equal(t, "US", info.Address.Country)
+ },
+ },
+ {
+ description: "address scope with invalid JSON omits address",
+ scope: "openid,address",
+ mutate: func(u *repository.OidcUserinfo) { u.Address = "not-valid-json" },
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Nil(t, info.Address)
+ },
+ },
+ {
+ description: "groups scope returns split groups",
+ scope: "openid,groups",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, []string{"admins", "users"}, info.Groups)
+ },
+ },
+ {
+ description: "groups scope returns empty slice when no groups",
+ scope: "openid,groups",
+ mutate: func(u *repository.OidcUserinfo) { u.Groups = "" },
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, []string{}, info.Groups)
+ },
+ },
+ {
+ description: "all scopes return all fields",
+ scope: "openid,profile,email,phone,address,groups",
+ run: func(t *testing.T, info service.UserinfoResponse) {
+ assert.Equal(t, "Test User", info.Name)
+ assert.Equal(t, "test@example.com", info.Email)
+ assert.Equal(t, "+15555550100", info.PhoneNumber)
+ require.NotNil(t, info.PhoneNumberVerified)
+ assert.True(t, *info.PhoneNumberVerified)
+ require.NotNil(t, info.Address)
+ assert.Equal(t, "Springfield", info.Address.Locality)
+ assert.Equal(t, []string{"admins", "users"}, info.Groups)
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.description, func(t *testing.T) {
+ user := newTestUser()
+ if test.mutate != nil {
+ test.mutate(&user)
+ }
+ info := svc.CompileUserinfo(user, test.scope)
+ test.run(t, info)
+ })
+ }
+}
diff --git a/internal/utils/app_utils.go b/internal/utils/app_utils.go
index 0cbc16eb..6b0ee834 100644
--- a/internal/utils/app_utils.go
+++ b/internal/utils/app_utils.go
@@ -7,8 +7,8 @@ import (
"net/url"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin"
"github.com/weppos/publicsuffix-go/publicsuffix"
diff --git a/internal/utils/app_utils_test.go b/internal/utils/app_utils_test.go
index 5ca545d5..a44c08d3 100644
--- a/internal/utils/app_utils_test.go
+++ b/internal/utils/app_utils_test.go
@@ -3,8 +3,8 @@ package utils_test
import (
"testing"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/gin-gonic/gin"
"gotest.tools/v3/assert"
diff --git a/internal/utils/decoders/label_decoder_test.go b/internal/utils/decoders/label_decoder_test.go
index fb63552e..bf5d49fd 100644
--- a/internal/utils/decoders/label_decoder_test.go
+++ b/internal/utils/decoders/label_decoder_test.go
@@ -3,8 +3,8 @@ package decoders_test
import (
"testing"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/decoders"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/decoders"
"gotest.tools/v3/assert"
)
diff --git a/internal/utils/label_utils_test.go b/internal/utils/label_utils_test.go
index 8edac795..1d1554bb 100644
--- a/internal/utils/label_utils_test.go
+++ b/internal/utils/label_utils_test.go
@@ -3,7 +3,7 @@ package utils_test
import (
"testing"
- "github.com/steveiliop56/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert"
)
diff --git a/internal/utils/loaders/loader_env.go b/internal/utils/loaders/loader_env.go
index 45c5b5ef..f441ddda 100644
--- a/internal/utils/loaders/loader_env.go
+++ b/internal/utils/loaders/loader_env.go
@@ -4,7 +4,7 @@ import (
"fmt"
"os"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/paerser/cli"
"github.com/tinyauthapp/paerser/env"
diff --git a/internal/utils/security_utils_test.go b/internal/utils/security_utils_test.go
index 3ebd6818..48c37335 100644
--- a/internal/utils/security_utils_test.go
+++ b/internal/utils/security_utils_test.go
@@ -4,7 +4,7 @@ import (
"os"
"testing"
- "github.com/steveiliop56/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert"
)
diff --git a/internal/utils/string_utils_test.go b/internal/utils/string_utils_test.go
index b5e41f89..1db3bf17 100644
--- a/internal/utils/string_utils_test.go
+++ b/internal/utils/string_utils_test.go
@@ -3,7 +3,7 @@ package utils_test
import (
"testing"
- "github.com/steveiliop56/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert"
)
diff --git a/internal/utils/tlog/log_wrapper.go b/internal/utils/tlog/log_wrapper.go
index 1b9c643a..e3220e40 100644
--- a/internal/utils/tlog/log_wrapper.go
+++ b/internal/utils/tlog/log_wrapper.go
@@ -7,7 +7,7 @@ import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
)
type Logger struct {
diff --git a/internal/utils/tlog/log_wrapper_test.go b/internal/utils/tlog/log_wrapper_test.go
index 1ba521c0..2db9e2a6 100644
--- a/internal/utils/tlog/log_wrapper_test.go
+++ b/internal/utils/tlog/log_wrapper_test.go
@@ -5,8 +5,8 @@ import (
"encoding/json"
"testing"
- "github.com/steveiliop56/tinyauth/internal/config"
- "github.com/steveiliop56/tinyauth/internal/utils/tlog"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/rs/zerolog"
"gotest.tools/v3/assert"
diff --git a/internal/utils/user_utils.go b/internal/utils/user_utils.go
index e0254c04..d80c655d 100644
--- a/internal/utils/user_utils.go
+++ b/internal/utils/user_utils.go
@@ -6,10 +6,10 @@ import (
"net/mail"
"strings"
- "github.com/steveiliop56/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/config"
)
-func ParseUsers(usersStr []string) ([]config.User, error) {
+func ParseUsers(usersStr []string, userAttributes map[string]config.UserAttributes) ([]config.User, error) {
var users []config.User
if len(usersStr) == 0 {
@@ -24,13 +24,16 @@ func ParseUsers(usersStr []string) ([]config.User, error) {
if err != nil {
return []config.User{}, err
}
+ if attrs, ok := userAttributes[parsed.Username]; ok {
+ parsed.Attributes = attrs
+ }
users = append(users, parsed)
}
return users, nil
}
-func GetUsers(usersCfg []string, usersPath string) ([]config.User, error) {
+func GetUsers(usersCfg []string, usersPath string, userAttributes map[string]config.UserAttributes) ([]config.User, error) {
var usersStr []string
if len(usersCfg) == 0 && usersPath == "" {
@@ -59,7 +62,7 @@ func GetUsers(usersCfg []string, usersPath string) ([]config.User, error) {
}
}
- return ParseUsers(usersStr)
+ return ParseUsers(usersStr, userAttributes)
}
func ParseUser(userStr string) (config.User, error) {
diff --git a/internal/utils/user_utils_test.go b/internal/utils/user_utils_test.go
index 658fbdc0..dcbb75cf 100644
--- a/internal/utils/user_utils_test.go
+++ b/internal/utils/user_utils_test.go
@@ -4,122 +4,117 @@ import (
"os"
"testing"
- "github.com/steveiliop56/tinyauth/internal/utils"
+ "github.com/tinyauthapp/tinyauth/internal/config"
+ "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert"
)
func TestGetUsers(t *testing.T) {
+ hash := "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G"
+
// Setup
file, err := os.Create("/tmp/tinyauth_users_test.txt")
assert.NilError(t, err)
- _, err = file.WriteString(" user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G \n user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G ") // Spacing is on purpose
+ _, err = file.WriteString(" user1:" + hash + " \n user2:" + hash + " ") // Spacing is on purpose
assert.NilError(t, err)
err = file.Close()
assert.NilError(t, err)
defer os.Remove("/tmp/tinyauth_users_test.txt")
- // Test file
- users, err := utils.GetUsers([]string{}, "/tmp/tinyauth_users_test.txt")
+ noAttrs := map[string]config.UserAttributes{}
+
+ // Test file only
+ users, err := utils.GetUsers([]string{}, "/tmp/tinyauth_users_test.txt", noAttrs)
assert.NilError(t, err)
assert.Equal(t, 2, len(users))
assert.Equal(t, "user1", users[0].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[0].Password)
+ assert.Equal(t, hash, users[0].Password)
assert.Equal(t, "user2", users[1].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
+ assert.Equal(t, hash, users[1].Password)
- // Test config
- users, err = utils.GetUsers([]string{"user3:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", "user4:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G"}, "")
+ // Test inline config only
+ users, err = utils.GetUsers([]string{"user3:" + hash, "user4:" + hash}, "", noAttrs)
assert.NilError(t, err)
assert.Equal(t, 2, len(users))
-
assert.Equal(t, "user3", users[0].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[0].Password)
assert.Equal(t, "user4", users[1].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
// Test both
- users, err = utils.GetUsers([]string{"user5:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G"}, "/tmp/tinyauth_users_test.txt")
+ users, err = utils.GetUsers([]string{"user5:" + hash}, "/tmp/tinyauth_users_test.txt", noAttrs)
assert.NilError(t, err)
assert.Equal(t, 3, len(users))
- assert.Equal(t, "user5", users[0].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[0].Password)
- assert.Equal(t, "user1", users[1].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
- assert.Equal(t, "user2", users[2].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[2].Password)
+ usernames := map[string]bool{}
+ for _, u := range users {
+ usernames[u.Username] = true
+ }
+ assert.Assert(t, usernames["user1"])
+ assert.Assert(t, usernames["user2"])
+ assert.Assert(t, usernames["user5"])
+
+ // Test attributes applied from userAttributes map
+ attrs := map[string]config.UserAttributes{
+ "user1": {Name: "User One", Email: "user1@example.com"},
+ }
+ users, err = utils.GetUsers([]string{}, "/tmp/tinyauth_users_test.txt", attrs)
+
+ assert.NilError(t, err)
+ assert.Equal(t, 2, len(users))
+
+ for _, u := range users {
+ if u.Username == "user1" {
+ assert.Equal(t, "User One", u.Attributes.Name)
+ assert.Equal(t, "user1@example.com", u.Attributes.Email)
+ }
+ if u.Username == "user2" {
+ assert.Equal(t, "", u.Attributes.Name)
+ }
+ }
// Test empty
- users, err = utils.GetUsers([]string{}, "")
+ users, err = utils.GetUsers([]string{}, "", noAttrs)
assert.NilError(t, err)
assert.Equal(t, 0, len(users))
// Test non-existent file
- users, err = utils.GetUsers([]string{}, "/tmp/non_existent_file.txt")
+ users, err = utils.GetUsers([]string{}, "/tmp/non_existent_file.txt", noAttrs)
assert.ErrorContains(t, err, "no such file or directory")
assert.Equal(t, 0, len(users))
}
-func TestParseUsers(t *testing.T) {
- // Valid users
- users, err := utils.ParseUsers([]string{"user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", "user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF"}) // user2 has TOTP
-
- assert.NilError(t, err)
-
- assert.Equal(t, 2, len(users))
-
- assert.Equal(t, "user1", users[0].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[0].Password)
- assert.Equal(t, "", users[0].TotpSecret)
- assert.Equal(t, "user2", users[1].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
- assert.Equal(t, "ABCDEF", users[1].TotpSecret)
-
- // Valid weirdly spaced users
- users, err = utils.ParseUsers([]string{" user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G ", " user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF "}) // Spacing is on purpose
- assert.NilError(t, err)
-
- assert.Equal(t, 2, len(users))
-
- assert.Equal(t, "user1", users[0].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[0].Password)
- assert.Equal(t, "", users[0].TotpSecret)
- assert.Equal(t, "user2", users[1].Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
- assert.Equal(t, "ABCDEF", users[1].TotpSecret)
-}
-
func TestParseUser(t *testing.T) {
+ hash := "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G"
+
// Valid user without TOTP
- user, err := utils.ParseUser("user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G")
+ user, err := utils.ParseUser("user1:" + hash)
assert.NilError(t, err)
assert.Equal(t, "user1", user.Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", user.Password)
+ assert.Equal(t, hash, user.Password)
assert.Equal(t, "", user.TotpSecret)
// Valid user with TOTP
- user, err = utils.ParseUser("user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF")
+ user, err = utils.ParseUser("user2:" + hash + ":ABCDEF")
assert.NilError(t, err)
assert.Equal(t, "user2", user.Username)
- assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", user.Password)
+ assert.Equal(t, hash, user.Password)
assert.Equal(t, "ABCDEF", user.TotpSecret)
// Valid user with $$ in password
diff --git a/sql/oidc_queries.sql b/sql/oidc_queries.sql
index 4ceba2c0..67b7b95e 100644
--- a/sql/oidc_queries.sql
+++ b/sql/oidc_queries.sql
@@ -95,9 +95,22 @@ INSERT INTO "oidc_userinfo" (
"preferred_username",
"email",
"groups",
- "updated_at"
+ "updated_at",
+ "given_name",
+ "family_name",
+ "middle_name",
+ "nickname",
+ "profile",
+ "picture",
+ "website",
+ "gender",
+ "birthdate",
+ "zoneinfo",
+ "locale",
+ "phone_number",
+ "address"
) VALUES (
- ?, ?, ?, ?, ?, ?
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
RETURNING *;
diff --git a/sql/oidc_schemas.sql b/sql/oidc_schemas.sql
index e570d127..d9a7ba4e 100644
--- a/sql/oidc_schemas.sql
+++ b/sql/oidc_schemas.sql
@@ -22,10 +22,23 @@ CREATE TABLE IF NOT EXISTS "oidc_tokens" (
);
CREATE TABLE IF NOT EXISTS "oidc_userinfo" (
- "sub" TEXT NOT NULL UNIQUE PRIMARY KEY,
- "name" TEXT NOT NULL,
- "preferred_username" TEXT NOT NULL,
- "email" TEXT NOT NULL,
- "groups" TEXT NOT NULL,
- "updated_at" INTEGER NOT NULL
+ "sub" TEXT NOT NULL UNIQUE PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "preferred_username" TEXT NOT NULL,
+ "email" TEXT NOT NULL,
+ "groups" TEXT NOT NULL,
+ "updated_at" INTEGER NOT NULL,
+ "given_name" TEXT NOT NULL,
+ "family_name" TEXT NOT NULL,
+ "middle_name" TEXT NOT NULL,
+ "nickname" TEXT NOT NULL,
+ "profile" TEXT NOT NULL,
+ "picture" TEXT NOT NULL,
+ "website" TEXT NOT NULL,
+ "gender" TEXT NOT NULL,
+ "birthdate" TEXT NOT NULL,
+ "zoneinfo" TEXT NOT NULL,
+ "locale" TEXT NOT NULL,
+ "phone_number" TEXT NOT NULL,
+ "address" TEXT NOT NULL
);