Compare commits

..

5 Commits

Author SHA1 Message Date
Ryc O'Chet
1e6a06d6e7 fix issue templates 2026-04-12 21:56:33 +01:00
Ryc O'Chet
5e520b6f68 code 2026-04-12 21:51:28 +01:00
Ryc O'Chet
9339222252 infrastructure and docs 2026-04-12 21:50:46 +01:00
Scott McKendry
18c8413ea3 feat: support unsigned oidc request objects (#785) 2026-04-12 19:19:47 +03:00
Stavros
1117f35496 refactor: use plain input for totp input to fix autofill issues (#790)
* fix(ui): allow pw manager extensions to autofill totp

* chore: small ui fixes

* fix: prevent double totp submissions

---------

Co-authored-by: Scott McKendry <me@scottmckendry.tech>
2026-04-12 19:12:21 +03:00
74 changed files with 259 additions and 404 deletions

View File

@@ -3,7 +3,8 @@ name: Bug report
about: Create a report to help improve Tinyauth about: Create a report to help improve Tinyauth
title: "[BUG]" title: "[BUG]"
labels: bug labels: bug
assignees: steveiliop56 assignees:
- steveiliop56
--- ---

View File

@@ -3,7 +3,8 @@ name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
title: "[FEATURE]" title: "[FEATURE]"
labels: enhancement labels: enhancement
assignees: steveiliop56 assignees:
- steveiliop56
--- ---

View File

@@ -80,7 +80,7 @@ jobs:
- name: Build - name: Build
run: | run: |
cp -r frontend/dist internal/assets/dist 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: env:
CGO_ENABLED: 0 CGO_ENABLED: 0
@@ -126,7 +126,7 @@ jobs:
- name: Build - name: Build
run: | run: |
cp -r frontend/dist internal/assets/dist 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: env:
CGO_ENABLED: 0 CGO_ENABLED: 0

View File

@@ -56,7 +56,7 @@ jobs:
- name: Build - name: Build
run: | run: |
cp -r frontend/dist internal/assets/dist 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: env:
CGO_ENABLED: 0 CGO_ENABLED: 0
@@ -99,7 +99,7 @@ jobs:
- name: Build - name: Build
run: | run: |
cp -r frontend/dist internal/assets/dist 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: env:
CGO_ENABLED: 0 CGO_ENABLED: 0

View File

@@ -15,7 +15,7 @@ Contributing to Tinyauth is straightforward. Follow the steps below to set up a
Start by cloning the repository: Start by cloning the repository:
```sh ```sh
git clone https://github.com/steveiliop56/tinyauth git clone https://github.com/tinyauthapp/tinyauth
cd tinyauth cd tinyauth
``` ```

View File

@@ -38,9 +38,9 @@ COPY ./internal ./internal
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
RUN CGO_ENABLED=0 go build -ldflags "-s -w \ RUN CGO_ENABLED=0 go build -ldflags "-s -w \
-X github.com/steveiliop56/tinyauth/internal/config.Version=${VERSION} \ -X github.com/tinyauthapp/tinyauth/internal/config.Version=${VERSION} \
-X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \ -X github.com/tinyauthapp/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.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
# Runner # Runner
FROM alpine:3.23 AS runner FROM alpine:3.23 AS runner

View File

@@ -40,9 +40,9 @@ COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
RUN mkdir -p data RUN mkdir -p data
RUN CGO_ENABLED=0 go build -ldflags "-s -w \ RUN CGO_ENABLED=0 go build -ldflags "-s -w \
-X github.com/steveiliop56/tinyauth/internal/config.Version=${VERSION} \ -X github.com/tinyauthapp/tinyauth/internal/config.Version=${VERSION} \
-X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \ -X github.com/tinyauthapp/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.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
# Runner # Runner
FROM gcr.io/distroless/static-debian12:latest AS runner FROM gcr.io/distroless/static-debian12:latest AS runner

View File

@@ -37,9 +37,9 @@ webui: clean-webui
# Build the binary # Build the binary
binary: webui binary: webui
CGO_ENABLED=$(CGO_ENABLED) go build -ldflags "-s -w \ CGO_ENABLED=$(CGO_ENABLED) go build -ldflags "-s -w \
-X github.com/steveiliop56/tinyauth/internal/config.Version=${TAG_NAME} \ -X github.com/tinyauthapp/tinyauth/internal/config.Version=${TAG_NAME} \
-X github.com/steveiliop56/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \ -X github.com/tinyauthapp/tinyauth/internal/config.CommitHash=${COMMIT_HASH} \
-X github.com/steveiliop56/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" \ -X github.com/tinyauthapp/tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}" \
-o ${BIN_NAME} ./cmd/tinyauth -o ${BIN_NAME} ./cmd/tinyauth
# Build for amd64 # Build for amd64

View File

@@ -5,10 +5,10 @@
</div> </div>
<div align="center"> <div align="center">
<img alt="License" src="https://img.shields.io/github/license/steveiliop56/tinyauth"> <img alt="License" src="https://img.shields.io/github/license/tinyauthapp/tinyauth">
<img alt="Release" src="https://img.shields.io/github/v/release/steveiliop56/tinyauth"> <img alt="Release" src="https://img.shields.io/github/v/release/tinyauthapp/tinyauth">
<img alt="Issues" src="https://img.shields.io/github/issues/steveiliop56/tinyauth"> <img alt="Issues" src="https://img.shields.io/github/issues/tinyauthapp/tinyauth">
<img alt="Tinyauth CI" src="https://github.com/steveiliop56/tinyauth/actions/workflows/ci.yml/badge.svg"> <img alt="Tinyauth CI" src="https://github.com/tinyauthapp/tinyauth/actions/workflows/ci.yml/badge.svg">
<a title="Crowdin" target="_blank" href="https://crowdin.com/project/tinyauth"><img src="https://badges.crowdin.net/tinyauth/localized.svg"></a> <a title="Crowdin" target="_blank" href="https://crowdin.com/project/tinyauth"><img src="https://badges.crowdin.net/tinyauth/localized.svg"></a>
</div> </div>
@@ -39,7 +39,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). 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/tinyauth-docs).
## Discord ## Discord
@@ -47,7 +47,7 @@ Tinyauth has a [Discord](https://discord.gg/eHzVaCzRRd) server. Feel free to hop
## Contributing ## 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 ## Localization
@@ -72,4 +72,4 @@ A big thank you to the following people for providing me with more coffee:
## Star History ## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=steveiliop56/tinyauth&type=Date)](https://www.star-history.com/#steveiliop56/tinyauth&Date) [![Star History Chart](https://api.star-history.com/svg?repos=tinyauthapp/tinyauth&type=Date)](https://www.star-history.com/#tinyauthapp/tinyauth&Date)

View File

@@ -2,7 +2,7 @@
## Supported Versions ## 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 ## Reporting a Vulnerability

View File

@@ -3,7 +3,7 @@
"embeds": [ "embeds": [
{ {
"title": "Welcome to Tinyauth Discord!", "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: <https://github.com/steveiliop56/tinyauth>\n• Website: <https://tinyauth.app>", "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: <https://github.com/tinyauthapp/tinyauth>\n• Website: <https://tinyauth.app>",
"url": "https://tinyauth.app", "url": "https://tinyauth.app",
"color": 7002085, "color": 7002085,
"author": { "author": {
@@ -14,9 +14,9 @@
}, },
"timestamp": "2025-06-06T12:25:27.629Z", "timestamp": "2025-06-06T12:25:27.629Z",
"thumbnail": { "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": [] "attachments": []
} }

View File

@@ -7,7 +7,7 @@ import (
"strings" "strings"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/tinyauthapp/paerser/cli" "github.com/tinyauthapp/paerser/cli"
) )

View File

@@ -6,7 +6,7 @@ import (
"strings" "strings"
"charm.land/huh/v2" "charm.land/huh/v2"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/tinyauthapp/paerser/cli" "github.com/tinyauthapp/paerser/cli"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )

View File

@@ -6,8 +6,8 @@ import (
"os" "os"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"charm.land/huh/v2" "charm.land/huh/v2"
"github.com/mdp/qrterminal/v3" "github.com/mdp/qrterminal/v3"

View File

@@ -9,7 +9,7 @@ import (
"os" "os"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/tinyauthapp/paerser/cli" "github.com/tinyauthapp/paerser/cli"
) )

View File

@@ -4,10 +4,10 @@ import (
"fmt" "fmt"
"charm.land/huh/v2" "charm.land/huh/v2"
"github.com/steveiliop56/tinyauth/internal/bootstrap" "github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/loaders" "github.com/tinyauthapp/tinyauth/internal/utils/loaders"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/tinyauthapp/paerser/cli" "github.com/tinyauthapp/paerser/cli"

View File

@@ -4,8 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"charm.land/huh/v2" "charm.land/huh/v2"
"github.com/pquerna/otp/totp" "github.com/pquerna/otp/totp"

View File

@@ -3,7 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/paerser/cli" "github.com/tinyauthapp/paerser/cli"
) )

View File

@@ -15,7 +15,7 @@ services:
traefik.http.routers.whoami.middlewares: tinyauth traefik.http.routers.whoami.middlewares: tinyauth
tinyauth: tinyauth:
image: ghcr.io/steveiliop56/tinyauth:v5 image: ghcr.io/tinyauthapp/tinyauth:v5
environment: environment:
- TINYAUTH_APPURL=https://tinyauth.example.com - TINYAUTH_APPURL=https://tinyauth.example.com
- TINYAUTH_AUTH_USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password - TINYAUTH_AUTH_USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password

View File

@@ -19,7 +19,6 @@
"i18next": "^26.0.3", "i18next": "^26.0.3",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.1", "i18next-resources-to-backend": "^1.2.1",
"input-otp": "^1.4.2",
"lucide-react": "^1.7.0", "lucide-react": "^1.7.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"radix-ui": "^1.4.3", "radix-ui": "^1.4.3",
@@ -623,8 +622,6 @@
"inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="],
"input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="],
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
"is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="],

View File

@@ -25,7 +25,6 @@
"i18next": "^26.0.3", "i18next": "^26.0.3",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.1", "i18next-resources-to-backend": "^1.2.1",
"input-otp": "^1.4.2",
"lucide-react": "^1.7.0", "lucide-react": "^1.7.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"radix-ui": "^1.4.3", "radix-ui": "^1.4.3",

View File

@@ -1,14 +1,10 @@
import { Form, FormControl, FormField, FormItem } from "../ui/form"; import { Form, FormControl, FormField, FormItem } from "../ui/form";
import { import { Input } from "../ui/input";
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from "../ui/input-otp";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { totpSchema, TotpSchema } from "@/schemas/totp-schema"; import { totpSchema, TotpSchema } from "@/schemas/totp-schema";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useRef } from "react";
import z from "zod"; import z from "zod";
interface Props { interface Props {
@@ -19,6 +15,7 @@ interface Props {
export const TotpForm = (props: Props) => { export const TotpForm = (props: Props) => {
const { formId, onSubmit } = props; const { formId, onSubmit } = props;
const { t } = useTranslation(); const { t } = useTranslation();
const autoSubmittedRef = useRef(false);
z.config({ z.config({
customError: (iss) => customError: (iss) =>
@@ -29,14 +26,19 @@ export const TotpForm = (props: Props) => {
resolver: zodResolver(totpSchema), resolver: zodResolver(totpSchema),
}); });
const handleChange = (value: string) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
form.setValue("code", value, { shouldDirty: true, shouldValidate: true }); const value = e.target.value.replace(/\D/g, "").slice(0, 6);
form.setValue("code", value, { shouldDirty: true, shouldValidate: false });
if (value.length === 6) { if (value.length === 6 && !autoSubmittedRef.current) {
onSubmit({ code: value }); autoSubmittedRef.current = true;
form.handleSubmit(onSubmit)();
return;
} }
autoSubmittedRef.current = false;
}; };
// Note: This is not the best UX, ideally we would want https://github.com/guilhermerodz/input-otp
// but some password managers cannot autofill the inputs (see #92) so, simple input it is
return ( return (
<Form {...form}> <Form {...form}>
<form id={formId} onSubmit={form.handleSubmit(onSubmit)}> <form id={formId} onSubmit={form.handleSubmit(onSubmit)}>
@@ -46,25 +48,17 @@ export const TotpForm = (props: Props) => {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormControl> <FormControl>
<InputOTP <Input
maxLength={6}
{...field} {...field}
type="text"
inputMode="numeric"
autoComplete="one-time-code" autoComplete="one-time-code"
autoFocus autoFocus
maxLength={6}
placeholder="XXXXXX"
onChange={handleChange} onChange={handleChange}
> className="text-center"
<InputOTPGroup> />
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
</FormControl> </FormControl>
</FormItem> </FormItem>
)} )}

View File

@@ -1,75 +0,0 @@
import * as React from "react";
import { OTPInput, OTPInputContext } from "input-otp";
import { MinusIcon } from "lucide-react";
import { cn } from "@/lib/utils";
function InputOTP({
className,
containerClassName,
...props
}: React.ComponentProps<typeof OTPInput> & {
containerClassName?: string;
}) {
return (
<OTPInput
data-slot="input-otp"
containerClassName={cn(
"flex items-center gap-2 has-disabled:opacity-50",
containerClassName,
)}
className={cn("disabled:cursor-not-allowed", className)}
{...props}
/>
);
}
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="input-otp-group"
className={cn("flex items-center", className)}
{...props}
/>
);
}
function InputOTPSlot({
index,
className,
...props
}: React.ComponentProps<"div"> & {
index: number;
}) {
const inputOTPContext = React.useContext(OTPInputContext);
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
return (
<div
data-slot="input-otp-slot"
data-active={isActive}
className={cn(
"data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
className,
)}
{...props}
>
{char}
{hasFakeCaret && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
</div>
)}
</div>
);
}
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
return (
<div data-slot="input-otp-separator" role="separator" {...props}>
<MinusIcon />
</div>
);
}
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };

View File

@@ -11,6 +11,33 @@ export const oidcParamsSchema = z.object({
code_challenge_method: z.string().optional(), code_challenge_method: z.string().optional(),
}); });
function b64urlDecode(s: string): string {
const base64 = s.replace(/-/g, "+").replace(/_/g, "/");
return atob(base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), "="));
}
function decodeRequestObject(jwt: string): Record<string, string> {
try {
// Must have exactly 3 parts: header, payload, signature
const parts = jwt.split(".");
if (parts.length !== 3) return {};
// Header must specify "alg": "none" and signature must be empty string
const header = JSON.parse(b64urlDecode(parts[0]));
if (!header || typeof header !== "object" || header.alg !== "none" || parts[2] !== "") return {};
const payload = JSON.parse(b64urlDecode(parts[1]));
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return {};
const result: Record<string, string> = {};
for (const [k, v] of Object.entries(payload)) {
if (typeof v === "string") result[k] = v;
}
return result;
} catch {
return {};
}
}
export const useOIDCParams = ( export const useOIDCParams = (
params: URLSearchParams, params: URLSearchParams,
): { ): {
@@ -20,6 +47,15 @@ export const useOIDCParams = (
compiled: string; compiled: string;
} => { } => {
const obj = Object.fromEntries(params.entries()); const obj = Object.fromEntries(params.entries());
// RFC 9101 / OIDC Core 6.1: if `request` param present, decode JWT payload
// and merge claims over top-level params (JWT claims take precedence)
const requestJwt = params.get("request");
if (requestJwt) {
const claims = decodeRequestObject(requestJwt);
Object.assign(obj, claims);
}
const parsed = oidcParamsSchema.safeParse(obj); const parsed = oidcParamsSchema.safeParse(obj);
if (parsed.success) { if (parsed.success) {

View File

@@ -74,7 +74,7 @@ export const TotpPage = () => {
<CardTitle className="text-xl">{t("totpTitle")}</CardTitle> <CardTitle className="text-xl">{t("totpTitle")}</CardTitle>
<CardDescription>{t("totpSubtitle")}</CardDescription> <CardDescription>{t("totpSubtitle")}</CardDescription>
</CardHeader> </CardHeader>
<CardContent className="flex flex-col items-center"> <CardContent>
<TotpForm <TotpForm
formId={formId} formId={formId}
onSubmit={(values) => totpMutation.mutate(values)} onSubmit={(values) => totpMutation.mutate(values)}

View File

@@ -10,7 +10,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
) )
type EnvEntry struct { type EnvEntry struct {

View File

@@ -10,7 +10,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
) )
type MarkdownEntry struct { type MarkdownEntry struct {

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/steveiliop56/tinyauth module github.com/tinyauthapp/tinyauth
go 1.26.0 go 1.26.0

View File

@@ -1 +0,0 @@
ALTER TABLE "oidc_tokens" DROP COLUMN "code_hash";

View File

@@ -1 +0,0 @@
ALTER TABLE "oidc_tokens" ADD COLUMN "code_hash" TEXT DEFAULT "";

View File

@@ -12,11 +12,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
) )
type BootstrapApp struct { type BootstrapApp struct {

View File

@@ -6,7 +6,7 @@ import (
"os" "os"
"path/filepath" "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"
"github.com/golang-migrate/migrate/v4/database/sqlite3" "github.com/golang-migrate/migrate/v4/database/sqlite3"

View File

@@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"slices" "slices"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/middleware" "github.com/tinyauthapp/tinyauth/internal/middleware"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )

View File

@@ -1,9 +1,9 @@
package bootstrap package bootstrap
import ( import (
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
) )
type Services struct { type Services struct {

View File

@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )

View File

@@ -7,10 +7,10 @@ import (
"testing" "testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@@ -7,8 +7,8 @@ import (
"testing" "testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@@ -6,11 +6,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"

View File

@@ -10,9 +10,9 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
) )
type OIDCControllerConfig struct{} type OIDCControllerConfig struct{}
@@ -275,9 +275,6 @@ func (controller *OIDCController) Token(c *gin.Context) {
case "authorization_code": case "authorization_code":
entry, err := controller.oidc.GetCodeEntry(c, controller.oidc.Hash(req.Code), client.ClientID) entry, err := controller.oidc.GetCodeEntry(c, controller.oidc.Hash(req.Code), client.ClientID)
if err != nil { if err != nil {
// Delete the access token just in case
controller.oidc.DeleteTokenByCodeHash(c, controller.oidc.Hash(req.Code))
if errors.Is(err, service.ErrCodeNotFound) { if errors.Is(err, service.ErrCodeNotFound) {
tlog.App.Warn().Msg("Code not found") tlog.App.Warn().Msg("Code not found")
c.JSON(400, gin.H{ c.JSON(400, gin.H{

View File

@@ -12,12 +12,12 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
"github.com/steveiliop56/tinyauth/internal/bootstrap" "github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -778,74 +778,6 @@ func TestOIDCController(t *testing.T) {
assert.NotEmpty(t, error) assert.NotEmpty(t, error)
}, },
}, },
{
description: "Ensure access token gets invalidated on double code use",
middlewares: []gin.HandlerFunc{
simpleCtx,
},
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
authorizeCodeTest, found := getTestByDescription("Ensure authorize succeeds with valid params")
assert.True(t, found, "Authorize test not found")
authorizeCodeTest(t, router, recorder)
var res map[string]any
err := json.Unmarshal(recorder.Body.Bytes(), &res)
assert.NoError(t, err)
redirectURI := res["redirect_uri"].(string)
url, err := url.Parse(redirectURI)
assert.NoError(t, err)
queryParams := url.Query()
code := queryParams.Get("code")
assert.NotEmpty(t, code)
reqBody := controller.TokenRequest{
GrantType: "authorization_code",
Code: code,
RedirectURI: "https://test.example.com/callback",
}
reqBodyEncoded, err := query.Values(reqBody)
assert.NoError(t, err)
req := httptest.NewRequest("POST", "/api/oidc/token", strings.NewReader(reqBodyEncoded.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth("some-client-id", "some-client-secret")
recorder = httptest.NewRecorder()
router.ServeHTTP(recorder, req)
assert.Equal(t, 200, recorder.Code)
err = json.Unmarshal(recorder.Body.Bytes(), &res)
assert.NoError(t, err)
accessToken := res["access_token"].(string)
assert.NotEmpty(t, accessToken)
req = httptest.NewRequest("GET", "/api/oidc/userinfo", nil)
req.Header.Set("Authorization", "Bearer "+accessToken)
recorder = httptest.NewRecorder()
router.ServeHTTP(recorder, req)
assert.Equal(t, 200, recorder.Code)
req = httptest.NewRequest("POST", "/api/oidc/token", strings.NewReader(reqBodyEncoded.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth("some-client-id", "some-client-secret")
recorder = httptest.NewRecorder()
router.ServeHTTP(recorder, req)
assert.Equal(t, 400, recorder.Code)
req = httptest.NewRequest("GET", "/api/oidc/userinfo", nil)
req.Header.Set("Authorization", "Bearer "+accessToken)
recorder = httptest.NewRecorder()
router.ServeHTTP(recorder, req)
assert.Equal(t, 401, recorder.Code)
err = json.Unmarshal(recorder.Body.Bytes(), &res)
assert.NoError(t, err)
assert.Equal(t, "invalid_grant", res["error"])
},
},
} }
app := bootstrap.NewBootstrapApp(config.Config{}) app := bootstrap.NewBootstrapApp(config.Config{})

View File

@@ -8,10 +8,10 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"

View File

@@ -6,12 +6,12 @@ import (
"testing" "testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/steveiliop56/tinyauth/internal/bootstrap" "github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View File

@@ -7,8 +7,8 @@ import (
"testing" "testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View File

@@ -4,10 +4,10 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp" "github.com/pquerna/otp/totp"

View File

@@ -11,12 +11,12 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp" "github.com/pquerna/otp/totp"
"github.com/steveiliop56/tinyauth/internal/bootstrap" "github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View File

@@ -5,23 +5,25 @@ import (
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
) )
type OpenIDConnectConfiguration struct { type OpenIDConnectConfiguration struct {
Issuer string `json:"issuer"` Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"` AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"` TokenEndpoint string `json:"token_endpoint"`
UserinfoEndpoint string `json:"userinfo_endpoint"` UserinfoEndpoint string `json:"userinfo_endpoint"`
JwksUri string `json:"jwks_uri"` JwksUri string `json:"jwks_uri"`
ScopesSupported []string `json:"scopes_supported"` ScopesSupported []string `json:"scopes_supported"`
ResponseTypesSupported []string `json:"response_types_supported"` ResponseTypesSupported []string `json:"response_types_supported"`
GrantTypesSupported []string `json:"grant_types_supported"` GrantTypesSupported []string `json:"grant_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"` SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"` IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"` TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
ClaimsSupported []string `json:"claims_supported"` ClaimsSupported []string `json:"claims_supported"`
ServiceDocumentation string `json:"service_documentation"` ServiceDocumentation string `json:"service_documentation"`
RequestParameterSupported bool `json:"request_parameter_supported"`
RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported"`
} }
type WellKnownControllerConfig struct{} type WellKnownControllerConfig struct{}
@@ -48,19 +50,21 @@ func (controller *WellKnownController) SetupRoutes() {
func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context) { func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context) {
issuer := controller.oidc.GetIssuer() issuer := controller.oidc.GetIssuer()
c.JSON(200, OpenIDConnectConfiguration{ c.JSON(200, OpenIDConnectConfiguration{
Issuer: issuer, Issuer: issuer,
AuthorizationEndpoint: fmt.Sprintf("%s/authorize", issuer), AuthorizationEndpoint: fmt.Sprintf("%s/authorize", issuer),
TokenEndpoint: fmt.Sprintf("%s/api/oidc/token", issuer), TokenEndpoint: fmt.Sprintf("%s/api/oidc/token", issuer),
UserinfoEndpoint: fmt.Sprintf("%s/api/oidc/userinfo", issuer), UserinfoEndpoint: fmt.Sprintf("%s/api/oidc/userinfo", issuer),
JwksUri: fmt.Sprintf("%s/.well-known/jwks.json", issuer), JwksUri: fmt.Sprintf("%s/.well-known/jwks.json", issuer),
ScopesSupported: service.SupportedScopes, ScopesSupported: service.SupportedScopes,
ResponseTypesSupported: service.SupportedResponseTypes, ResponseTypesSupported: service.SupportedResponseTypes,
GrantTypesSupported: service.SupportedGrantTypes, GrantTypesSupported: service.SupportedGrantTypes,
SubjectTypesSupported: []string{"pairwise"}, SubjectTypesSupported: []string{"pairwise"},
IDTokenSigningAlgValuesSupported: []string{"RS256"}, IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post"}, 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"},
ServiceDocumentation: "https://tinyauth.app/docs/guides/oidc", ServiceDocumentation: "https://tinyauth.app/docs/guides/oidc",
RequestParameterSupported: true,
RequestObjectSigningAlgValuesSupported: []string{"none"},
}) })
} }

View File

@@ -8,12 +8,12 @@ import (
"testing" "testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/steveiliop56/tinyauth/internal/bootstrap" "github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/controller" "github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -56,19 +56,21 @@ func TestWellKnownController(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
expected := controller.OpenIDConnectConfiguration{ expected := controller.OpenIDConnectConfiguration{
Issuer: oidcServiceCfg.Issuer, Issuer: oidcServiceCfg.Issuer,
AuthorizationEndpoint: fmt.Sprintf("%s/authorize", oidcServiceCfg.Issuer), AuthorizationEndpoint: fmt.Sprintf("%s/authorize", oidcServiceCfg.Issuer),
TokenEndpoint: fmt.Sprintf("%s/api/oidc/token", oidcServiceCfg.Issuer), TokenEndpoint: fmt.Sprintf("%s/api/oidc/token", oidcServiceCfg.Issuer),
UserinfoEndpoint: fmt.Sprintf("%s/api/oidc/userinfo", oidcServiceCfg.Issuer), UserinfoEndpoint: fmt.Sprintf("%s/api/oidc/userinfo", oidcServiceCfg.Issuer),
JwksUri: fmt.Sprintf("%s/.well-known/jwks.json", oidcServiceCfg.Issuer), JwksUri: fmt.Sprintf("%s/.well-known/jwks.json", oidcServiceCfg.Issuer),
ScopesSupported: service.SupportedScopes, ScopesSupported: service.SupportedScopes,
ResponseTypesSupported: service.SupportedResponseTypes, ResponseTypesSupported: service.SupportedResponseTypes,
GrantTypesSupported: service.SupportedGrantTypes, GrantTypesSupported: service.SupportedGrantTypes,
SubjectTypesSupported: []string{"pairwise"}, SubjectTypesSupported: []string{"pairwise"},
IDTokenSigningAlgValuesSupported: []string{"RS256"}, IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post"}, 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"},
ServiceDocumentation: "https://tinyauth.app/docs/guides/oidc", ServiceDocumentation: "https://tinyauth.app/docs/guides/oidc",
RequestParameterSupported: true,
RequestObjectSigningAlgValuesSupported: []string{"none"},
} }
assert.Equal(t, expected, res) assert.Equal(t, expected, res)

View File

@@ -4,10 +4,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/service" "github.com/tinyauthapp/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )

View File

@@ -8,8 +8,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/assets" "github.com/tinyauthapp/tinyauth/internal/assets"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )

View File

@@ -5,7 +5,7 @@ import (
"time" "time"
"github.com/gin-gonic/gin" "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 // See context middleware for explanation of why we have to do this

View File

@@ -19,7 +19,6 @@ type OidcToken struct {
Sub string Sub string
AccessTokenHash string AccessTokenHash string
RefreshTokenHash string RefreshTokenHash string
CodeHash string
Scope string Scope string
ClientID string ClientID string
TokenExpiresAt int64 TokenExpiresAt int64

View File

@@ -70,12 +70,11 @@ INSERT INTO "oidc_tokens" (
"client_id", "client_id",
"token_expires_at", "token_expires_at",
"refresh_token_expires_at", "refresh_token_expires_at",
"code_hash",
"nonce" "nonce"
) VALUES ( ) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?
) )
RETURNING sub, access_token_hash, refresh_token_hash, code_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce RETURNING sub, access_token_hash, refresh_token_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce
` `
type CreateOidcTokenParams struct { type CreateOidcTokenParams struct {
@@ -86,7 +85,6 @@ type CreateOidcTokenParams struct {
ClientID string ClientID string
TokenExpiresAt int64 TokenExpiresAt int64
RefreshTokenExpiresAt int64 RefreshTokenExpiresAt int64
CodeHash string
Nonce string Nonce string
} }
@@ -99,7 +97,6 @@ func (q *Queries) CreateOidcToken(ctx context.Context, arg CreateOidcTokenParams
arg.ClientID, arg.ClientID,
arg.TokenExpiresAt, arg.TokenExpiresAt,
arg.RefreshTokenExpiresAt, arg.RefreshTokenExpiresAt,
arg.CodeHash,
arg.Nonce, arg.Nonce,
) )
var i OidcToken var i OidcToken
@@ -107,7 +104,6 @@ func (q *Queries) CreateOidcToken(ctx context.Context, arg CreateOidcTokenParams
&i.Sub, &i.Sub,
&i.AccessTokenHash, &i.AccessTokenHash,
&i.RefreshTokenHash, &i.RefreshTokenHash,
&i.CodeHash,
&i.Scope, &i.Scope,
&i.ClientID, &i.ClientID,
&i.TokenExpiresAt, &i.TokenExpiresAt,
@@ -202,7 +198,7 @@ func (q *Queries) DeleteExpiredOidcCodes(ctx context.Context, expiresAt int64) (
const deleteExpiredOidcTokens = `-- name: DeleteExpiredOidcTokens :many const deleteExpiredOidcTokens = `-- name: DeleteExpiredOidcTokens :many
DELETE FROM "oidc_tokens" DELETE FROM "oidc_tokens"
WHERE "token_expires_at" < ? AND "refresh_token_expires_at" < ? WHERE "token_expires_at" < ? AND "refresh_token_expires_at" < ?
RETURNING sub, access_token_hash, refresh_token_hash, code_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce RETURNING sub, access_token_hash, refresh_token_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce
` `
type DeleteExpiredOidcTokensParams struct { type DeleteExpiredOidcTokensParams struct {
@@ -223,7 +219,6 @@ func (q *Queries) DeleteExpiredOidcTokens(ctx context.Context, arg DeleteExpired
&i.Sub, &i.Sub,
&i.AccessTokenHash, &i.AccessTokenHash,
&i.RefreshTokenHash, &i.RefreshTokenHash,
&i.CodeHash,
&i.Scope, &i.Scope,
&i.ClientID, &i.ClientID,
&i.TokenExpiresAt, &i.TokenExpiresAt,
@@ -273,16 +268,6 @@ func (q *Queries) DeleteOidcToken(ctx context.Context, accessTokenHash string) e
return err return err
} }
const deleteOidcTokenByCodeHash = `-- name: DeleteOidcTokenByCodeHash :exec
DELETE FROM "oidc_tokens"
WHERE "code_hash" = ?
`
func (q *Queries) DeleteOidcTokenByCodeHash(ctx context.Context, codeHash string) error {
_, err := q.db.ExecContext(ctx, deleteOidcTokenByCodeHash, codeHash)
return err
}
const deleteOidcTokenBySub = `-- name: DeleteOidcTokenBySub :exec const deleteOidcTokenBySub = `-- name: DeleteOidcTokenBySub :exec
DELETE FROM "oidc_tokens" DELETE FROM "oidc_tokens"
WHERE "sub" = ? WHERE "sub" = ?
@@ -390,7 +375,7 @@ func (q *Queries) GetOidcCodeUnsafe(ctx context.Context, codeHash string) (OidcC
} }
const getOidcToken = `-- name: GetOidcToken :one const getOidcToken = `-- name: GetOidcToken :one
SELECT sub, access_token_hash, refresh_token_hash, code_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce FROM "oidc_tokens" SELECT sub, access_token_hash, refresh_token_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce FROM "oidc_tokens"
WHERE "access_token_hash" = ? WHERE "access_token_hash" = ?
` `
@@ -401,7 +386,6 @@ func (q *Queries) GetOidcToken(ctx context.Context, accessTokenHash string) (Oid
&i.Sub, &i.Sub,
&i.AccessTokenHash, &i.AccessTokenHash,
&i.RefreshTokenHash, &i.RefreshTokenHash,
&i.CodeHash,
&i.Scope, &i.Scope,
&i.ClientID, &i.ClientID,
&i.TokenExpiresAt, &i.TokenExpiresAt,
@@ -412,7 +396,7 @@ func (q *Queries) GetOidcToken(ctx context.Context, accessTokenHash string) (Oid
} }
const getOidcTokenByRefreshToken = `-- name: GetOidcTokenByRefreshToken :one const getOidcTokenByRefreshToken = `-- name: GetOidcTokenByRefreshToken :one
SELECT sub, access_token_hash, refresh_token_hash, code_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce FROM "oidc_tokens" SELECT sub, access_token_hash, refresh_token_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce FROM "oidc_tokens"
WHERE "refresh_token_hash" = ? WHERE "refresh_token_hash" = ?
` `
@@ -423,7 +407,6 @@ func (q *Queries) GetOidcTokenByRefreshToken(ctx context.Context, refreshTokenHa
&i.Sub, &i.Sub,
&i.AccessTokenHash, &i.AccessTokenHash,
&i.RefreshTokenHash, &i.RefreshTokenHash,
&i.CodeHash,
&i.Scope, &i.Scope,
&i.ClientID, &i.ClientID,
&i.TokenExpiresAt, &i.TokenExpiresAt,
@@ -434,7 +417,7 @@ func (q *Queries) GetOidcTokenByRefreshToken(ctx context.Context, refreshTokenHa
} }
const getOidcTokenBySub = `-- name: GetOidcTokenBySub :one const getOidcTokenBySub = `-- name: GetOidcTokenBySub :one
SELECT sub, access_token_hash, refresh_token_hash, code_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce FROM "oidc_tokens" SELECT sub, access_token_hash, refresh_token_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce FROM "oidc_tokens"
WHERE "sub" = ? WHERE "sub" = ?
` `
@@ -445,7 +428,6 @@ func (q *Queries) GetOidcTokenBySub(ctx context.Context, sub string) (OidcToken,
&i.Sub, &i.Sub,
&i.AccessTokenHash, &i.AccessTokenHash,
&i.RefreshTokenHash, &i.RefreshTokenHash,
&i.CodeHash,
&i.Scope, &i.Scope,
&i.ClientID, &i.ClientID,
&i.TokenExpiresAt, &i.TokenExpiresAt,
@@ -481,7 +463,7 @@ UPDATE "oidc_tokens" SET
"token_expires_at" = ?, "token_expires_at" = ?,
"refresh_token_expires_at" = ? "refresh_token_expires_at" = ?
WHERE "refresh_token_hash" = ? WHERE "refresh_token_hash" = ?
RETURNING sub, access_token_hash, refresh_token_hash, code_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce RETURNING sub, access_token_hash, refresh_token_hash, scope, client_id, token_expires_at, refresh_token_expires_at, nonce
` `
type UpdateOidcTokenByRefreshTokenParams struct { type UpdateOidcTokenByRefreshTokenParams struct {
@@ -505,7 +487,6 @@ func (q *Queries) UpdateOidcTokenByRefreshToken(ctx context.Context, arg UpdateO
&i.Sub, &i.Sub,
&i.AccessTokenHash, &i.AccessTokenHash,
&i.RefreshTokenHash, &i.RefreshTokenHash,
&i.CodeHash,
&i.Scope, &i.Scope,
&i.ClientID, &i.ClientID,
&i.TokenExpiresAt, &i.TokenExpiresAt,

View File

@@ -4,8 +4,8 @@ import (
"errors" "errors"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
) )
type AccessControlsService struct { type AccessControlsService struct {

View File

@@ -10,10 +10,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"

View File

@@ -4,9 +4,9 @@ import (
"context" "context"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/decoders" "github.com/tinyauthapp/tinyauth/internal/utils/decoders"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
container "github.com/docker/docker/api/types/container" container "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client" "github.com/docker/docker/client"

View File

@@ -9,7 +9,7 @@ import (
"github.com/cenkalti/backoff/v5" "github.com/cenkalti/backoff/v5"
ldapgo "github.com/go-ldap/ldap/v3" ldapgo "github.com/go-ldap/ldap/v3"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
) )
type LdapServiceConfig struct { type LdapServiceConfig struct {

View File

@@ -1,8 +1,8 @@
package service package service
import ( import (
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"golang.org/x/oauth2" "golang.org/x/oauth2"

View File

@@ -8,7 +8,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
) )
type GithubEmailResponse []struct { type GithubEmailResponse []struct {

View File

@@ -1,7 +1,7 @@
package service package service
import ( import (
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"golang.org/x/oauth2/endpoints" "golang.org/x/oauth2/endpoints"
) )

View File

@@ -6,7 +6,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )

View File

@@ -20,10 +20,10 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/repository" "github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
@@ -506,7 +506,6 @@ func (service *OIDCService) GenerateAccessToken(c *gin.Context, client config.OI
TokenExpiresAt: tokenExpiresAt, TokenExpiresAt: tokenExpiresAt,
RefreshTokenExpiresAt: refrshTokenExpiresAt, RefreshTokenExpiresAt: refrshTokenExpiresAt,
Nonce: codeEntry.Nonce, Nonce: codeEntry.Nonce,
CodeHash: codeEntry.CodeHash,
}) })
if err != nil { if err != nil {
@@ -591,10 +590,6 @@ func (service *OIDCService) DeleteToken(c *gin.Context, tokenHash string) error
return service.queries.DeleteOidcToken(c, tokenHash) return service.queries.DeleteOidcToken(c, tokenHash)
} }
func (service *OIDCService) DeleteTokenByCodeHash(c *gin.Context, codeHash string) error {
return service.queries.DeleteOidcTokenByCodeHash(c, codeHash)
}
func (service *OIDCService) GetAccessToken(c *gin.Context, tokenHash string) (repository.OidcToken, error) { func (service *OIDCService) GetAccessToken(c *gin.Context, tokenHash string) (repository.OidcToken, error) {
entry, err := service.queries.GetOidcToken(c, tokenHash) entry, err := service.queries.GetOidcToken(c, tokenHash)

View File

@@ -7,8 +7,8 @@ import (
"net/url" "net/url"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/weppos/publicsuffix-go/publicsuffix" "github.com/weppos/publicsuffix-go/publicsuffix"

View File

@@ -3,8 +3,8 @@ package utils_test
import ( import (
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"

View File

@@ -3,8 +3,8 @@ package decoders_test
import ( import (
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/decoders" "github.com/tinyauthapp/tinyauth/internal/utils/decoders"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )

View File

@@ -3,7 +3,7 @@ package utils_test
import ( import (
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/paerser/cli" "github.com/tinyauthapp/paerser/cli"
"github.com/tinyauthapp/paerser/env" "github.com/tinyauthapp/paerser/env"

View File

@@ -4,7 +4,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )

View File

@@ -3,7 +3,7 @@ package utils_test
import ( import (
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )

View File

@@ -7,7 +7,7 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
) )
type Logger struct { type Logger struct {

View File

@@ -5,8 +5,8 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/utils/tlog" "github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"

View File

@@ -6,7 +6,7 @@ import (
"net/mail" "net/mail"
"strings" "strings"
"github.com/steveiliop56/tinyauth/internal/config" "github.com/tinyauthapp/tinyauth/internal/config"
) )
func ParseUsers(usersStr []string) ([]config.User, error) { func ParseUsers(usersStr []string) ([]config.User, error) {

View File

@@ -4,7 +4,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/steveiliop56/tinyauth/internal/utils" "github.com/tinyauthapp/tinyauth/internal/utils"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )

View File

@@ -48,10 +48,9 @@ INSERT INTO "oidc_tokens" (
"client_id", "client_id",
"token_expires_at", "token_expires_at",
"refresh_token_expires_at", "refresh_token_expires_at",
"code_hash",
"nonce" "nonce"
) VALUES ( ) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?
) )
RETURNING *; RETURNING *;
@@ -76,10 +75,6 @@ WHERE "refresh_token_hash" = ?;
SELECT * FROM "oidc_tokens" SELECT * FROM "oidc_tokens"
WHERE "sub" = ?; WHERE "sub" = ?;
-- name: DeleteOidcTokenByCodeHash :exec
DELETE FROM "oidc_tokens"
WHERE "code_hash" = ?;
-- name: DeleteOidcToken :exec -- name: DeleteOidcToken :exec
DELETE FROM "oidc_tokens" DELETE FROM "oidc_tokens"
WHERE "access_token_hash" = ?; WHERE "access_token_hash" = ?;

View File

@@ -13,7 +13,6 @@ CREATE TABLE IF NOT EXISTS "oidc_tokens" (
"sub" TEXT NOT NULL UNIQUE, "sub" TEXT NOT NULL UNIQUE,
"access_token_hash" TEXT NOT NULL PRIMARY KEY UNIQUE, "access_token_hash" TEXT NOT NULL PRIMARY KEY UNIQUE,
"refresh_token_hash" TEXT NOT NULL, "refresh_token_hash" TEXT NOT NULL,
"code_hash" TEXT NOT NULL,
"scope" TEXT NOT NULL, "scope" TEXT NOT NULL,
"client_id" TEXT NOT NULL, "client_id" TEXT NOT NULL,
"token_expires_at" INTEGER NOT NULL, "token_expires_at" INTEGER NOT NULL,