Compare commits

..

2 Commits

Author SHA1 Message Date
Stavros
90e093631a tests: extend testing for non browser detection in all proxies 2026-04-10 18:07:12 +03:00
Stavros
8137443bc1 fix: return 307 redirects for envoy proxy instead of 401 2026-04-10 18:00:52 +03:00
69 changed files with 363 additions and 340 deletions

View File

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

View File

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

View File

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

View File

@@ -56,7 +56,7 @@ jobs:
- name: Build
run: |
cp -r frontend/dist internal/assets/dist
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
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
env:
CGO_ENABLED: 0
@@ -99,7 +99,7 @@ jobs:
- name: Build
run: |
cp -r frontend/dist internal/assets/dist
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
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
env:
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:
```sh
git clone https://github.com/tinyauthapp/tinyauth
git clone https://github.com/steveiliop56/tinyauth
cd tinyauth
```

View File

@@ -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/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
-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
# 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 CGO_ENABLED=0 go build -ldflags "-s -w \
-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
-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
# Runner
FROM gcr.io/distroless/static-debian12:latest AS runner

View File

@@ -37,9 +37,9 @@ webui: clean-webui
# Build the binary
binary: webui
CGO_ENABLED=$(CGO_ENABLED) go build -ldflags "-s -w \
-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}" \
-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}" \
-o ${BIN_NAME} ./cmd/tinyauth
# Build for amd64

View File

@@ -5,10 +5,10 @@
</div>
<div align="center">
<img alt="License" src="https://img.shields.io/github/license/tinyauthapp/tinyauth">
<img alt="Release" src="https://img.shields.io/github/v/release/tinyauthapp/tinyauth">
<img alt="Issues" src="https://img.shields.io/github/issues/tinyauthapp/tinyauth">
<img alt="Tinyauth CI" src="https://github.com/tinyauthapp/tinyauth/actions/workflows/ci.yml/badge.svg">
<img alt="License" src="https://img.shields.io/github/license/steveiliop56/tinyauth">
<img alt="Release" src="https://img.shields.io/github/v/release/steveiliop56/tinyauth">
<img alt="Issues" src="https://img.shields.io/github/issues/steveiliop56/tinyauth">
<img alt="Tinyauth CI" src="https://github.com/steveiliop56/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>
</div>
@@ -24,9 +24,6 @@ Tinyauth is the simplest and tiniest authentication and authorization server you
> [!NOTE]
> This is the main development branch. For the latest stable release, see the [documentation](https://tinyauth.app) or the latest stable tag.
> [!NOTE]
> Tinyauth is in the process of migrating to the new [tinyauthapp](https://github.com/tinyauthapp) organization. The organization **is official** and it will host all of the Tinyauth related repositories in the future.
## Getting Started
You can get started with Tinyauth by following the guide in the [documentation](https://tinyauth.app/docs/getting-started). There is also an available [docker-compose](./docker-compose.example.yml) file that has Traefik, Whoami and Tinyauth to demonstrate its capabilities (keep in mind that this file lives in the development branch so it may have updates that are not yet released).
@@ -39,7 +36,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/tinyauthapp/tinyauth-docs).
If you wish to contribute to the documentation head over to the [repository](https://github.com/steveiliop56/tinyauth-docs).
## Discord
@@ -47,7 +44,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/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.
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.
## Localization
@@ -72,4 +69,4 @@ A big thank you to the following people for providing me with more coffee:
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=tinyauthapp/tinyauth&type=Date)](https://www.star-history.com/#tinyauthapp/tinyauth&Date)
[![Star History Chart](https://api.star-history.com/svg?repos=steveiliop56/tinyauth&type=Date)](https://www.star-history.com/#steveiliop56/tinyauth&Date)

View File

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

View File

@@ -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: <https://github.com/tinyauthapp/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/steveiliop56/tinyauth>\n• Website: <https://tinyauth.app>",
"url": "https://tinyauth.app",
"color": 7002085,
"author": {
@@ -14,9 +14,9 @@
},
"timestamp": "2025-06-06T12:25:27.629Z",
"thumbnail": {
"url": "https://github.com/tinyauthapp/tinyauth/blob/main/assets/logo.png?raw=true"
"url": "https://github.com/steveiliop56/tinyauth/blob/main/assets/logo.png?raw=true"
}
}
],
"attachments": []
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,10 +4,10 @@ import (
"fmt"
"charm.land/huh/v2"
"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/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/rs/zerolog/log"
"github.com/tinyauthapp/paerser/cli"

View File

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

View File

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

View File

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

View File

@@ -19,6 +19,7 @@
"i18next": "^26.0.3",
"i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.1",
"input-otp": "^1.4.2",
"lucide-react": "^1.7.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.4.3",
@@ -622,6 +623,8 @@
"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-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,6 +25,7 @@
"i18next": "^26.0.3",
"i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.1",
"input-otp": "^1.4.2",
"lucide-react": "^1.7.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.4.3",

View File

@@ -1,10 +1,14 @@
import { Form, FormControl, FormField, FormItem } from "../ui/form";
import { Input } from "../ui/input";
import {
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from "../ui/input-otp";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { totpSchema, TotpSchema } from "@/schemas/totp-schema";
import { useTranslation } from "react-i18next";
import { useRef } from "react";
import z from "zod";
interface Props {
@@ -15,7 +19,6 @@ interface Props {
export const TotpForm = (props: Props) => {
const { formId, onSubmit } = props;
const { t } = useTranslation();
const autoSubmittedRef = useRef(false);
z.config({
customError: (iss) =>
@@ -26,19 +29,14 @@ export const TotpForm = (props: Props) => {
resolver: zodResolver(totpSchema),
});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value.replace(/\D/g, "").slice(0, 6);
form.setValue("code", value, { shouldDirty: true, shouldValidate: false });
if (value.length === 6 && !autoSubmittedRef.current) {
autoSubmittedRef.current = true;
form.handleSubmit(onSubmit)();
return;
const handleChange = (value: string) => {
form.setValue("code", value, { shouldDirty: true, shouldValidate: true });
if (value.length === 6) {
onSubmit({ code: value });
}
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 (
<Form {...form}>
<form id={formId} onSubmit={form.handleSubmit(onSubmit)}>
@@ -48,17 +46,25 @@ export const TotpForm = (props: Props) => {
render={({ field }) => (
<FormItem>
<FormControl>
<Input
<InputOTP
maxLength={6}
{...field}
type="text"
inputMode="numeric"
autoComplete="one-time-code"
autoFocus
maxLength={6}
placeholder="XXXXXX"
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>
</FormItem>
)}

View File

@@ -0,0 +1,75 @@
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,33 +11,6 @@ export const oidcParamsSchema = z.object({
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 = (
params: URLSearchParams,
): {
@@ -47,15 +20,6 @@ export const useOIDCParams = (
compiled: string;
} => {
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);
if (parsed.success) {

View File

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

View File

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

View File

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

12
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/tinyauthapp/tinyauth
module github.com/steveiliop56/tinyauth
go 1.26.0
@@ -18,11 +18,11 @@ require (
github.com/stretchr/testify v1.11.1
github.com/tinyauthapp/paerser v0.0.0-20260410140347-85c3740d6298
github.com/weppos/publicsuffix-go v0.50.3
golang.org/x/crypto v0.50.0
golang.org/x/crypto v0.49.0
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.48.0
)
require (
@@ -119,9 +119,9 @@ require (
golang.org/x/arch v0.22.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/term v0.42.0 // indirect
golang.org/x/text v0.36.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/text v0.35.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

28
go.sum
View File

@@ -289,12 +289,12 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
@@ -302,16 +302,16 @@ golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
@@ -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.48.0 h1:ElZyLop3Q2mHYk5IFPPXADejZrlHu7APbpB0sF78bq4=
modernc.org/sqlite v1.48.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
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=

View File

@@ -12,11 +12,11 @@ import (
"strings"
"time"
"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"
"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"
)
type BootstrapApp struct {

View File

@@ -6,7 +6,7 @@ import (
"os"
"path/filepath"
"github.com/tinyauthapp/tinyauth/internal/assets"
"github.com/steveiliop56/tinyauth/internal/assets"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"

View File

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

View File

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

View File

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

View File

@@ -7,10 +7,10 @@ import (
"testing"
"github.com/gin-gonic/gin"
"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/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/stretchr/testify/assert"
)

View File

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

View File

@@ -6,11 +6,11 @@ import (
"strings"
"time"
"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/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/gin-gonic/gin"
"github.com/google/go-querystring/query"

View File

@@ -10,9 +10,9 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
"github.com/tinyauthapp/tinyauth/internal/service"
"github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/steveiliop56/tinyauth/internal/service"
"github.com/steveiliop56/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
)
type OIDCControllerConfig struct{}

View File

@@ -12,12 +12,12 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
"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/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/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

View File

@@ -8,10 +8,10 @@ import (
"regexp"
"strings"
"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/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/gin-gonic/gin"
"github.com/google/go-querystring/query"
@@ -131,21 +131,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
}
if !controller.auth.CheckIP(acls.IP, clientIP) {
queries, err := query.Values(config.UnauthorizedQuery{
Resource: strings.Split(proxyCtx.Host, ".")[0],
IP: clientIP,
})
if err != nil {
tlog.App.Error().Err(err).Msg("Failed to encode unauthorized query")
controller.handleError(c, proxyCtx)
return
}
redirectURL := fmt.Sprintf("%s/unauthorized?%s", controller.config.AppURL, queries.Encode())
if !controller.useBrowserResponse(proxyCtx) {
c.Header("x-tinyauth-location", redirectURL)
c.JSON(401, gin.H{
"status": 401,
"message": "Unauthorized",
@@ -153,7 +139,18 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
return
}
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
queries, err := query.Values(config.UnauthorizedQuery{
Resource: strings.Split(proxyCtx.Host, ".")[0],
IP: clientIP,
})
if err != nil {
tlog.App.Error().Err(err).Msg("Failed to encode unauthorized query")
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/error", controller.config.AppURL))
return
}
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/unauthorized?%s", controller.config.AppURL, queries.Encode()))
return
}
@@ -178,13 +175,21 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
if !userAllowed {
tlog.App.Warn().Str("user", userContext.Username).Str("resource", strings.Split(proxyCtx.Host, ".")[0]).Msg("User not allowed to access resource")
if !controller.useBrowserResponse(proxyCtx) {
c.JSON(403, gin.H{
"status": 403,
"message": "Forbidden",
})
return
}
queries, err := query.Values(config.UnauthorizedQuery{
Resource: strings.Split(proxyCtx.Host, ".")[0],
})
if err != nil {
tlog.App.Error().Err(err).Msg("Failed to encode unauthorized query")
controller.handleError(c, proxyCtx)
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/error", controller.config.AppURL))
return
}
@@ -194,18 +199,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
queries.Set("username", userContext.Username)
}
redirectURL := fmt.Sprintf("%s/unauthorized?%s", controller.config.AppURL, queries.Encode())
if !controller.useBrowserResponse(proxyCtx) {
c.Header("x-tinyauth-location", redirectURL)
c.JSON(403, gin.H{
"status": 403,
"message": "Forbidden",
})
return
}
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/unauthorized?%s", controller.config.AppURL, queries.Encode()))
return
}
@@ -221,6 +215,14 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
if !groupOK {
tlog.App.Warn().Str("user", userContext.Username).Str("resource", strings.Split(proxyCtx.Host, ".")[0]).Msg("User groups do not match resource requirements")
if !controller.useBrowserResponse(proxyCtx) {
c.JSON(403, gin.H{
"status": 403,
"message": "Forbidden",
})
return
}
queries, err := query.Values(config.UnauthorizedQuery{
Resource: strings.Split(proxyCtx.Host, ".")[0],
GroupErr: true,
@@ -228,7 +230,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
if err != nil {
tlog.App.Error().Err(err).Msg("Failed to encode unauthorized query")
controller.handleError(c, proxyCtx)
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/error", controller.config.AppURL))
return
}
@@ -238,18 +240,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
queries.Set("username", userContext.Username)
}
redirectURL := fmt.Sprintf("%s/unauthorized?%s", controller.config.AppURL, queries.Encode())
if !controller.useBrowserResponse(proxyCtx) {
c.Header("x-tinyauth-location", redirectURL)
c.JSON(403, gin.H{
"status": 403,
"message": "Forbidden",
})
return
}
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/unauthorized?%s", controller.config.AppURL, queries.Encode()))
return
}
}
@@ -275,20 +266,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
return
}
queries, err := query.Values(config.RedirectQuery{
RedirectURI: fmt.Sprintf("%s://%s%s", proxyCtx.Proto, proxyCtx.Host, proxyCtx.Path),
})
if err != nil {
tlog.App.Error().Err(err).Msg("Failed to encode redirect URI query")
controller.handleError(c, proxyCtx)
return
}
redirectURL := fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode())
if !controller.useBrowserResponse(proxyCtx) {
c.Header("x-tinyauth-location", redirectURL)
c.JSON(401, gin.H{
"status": 401,
"message": "Unauthorized",
@@ -296,7 +274,17 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
return
}
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
queries, err := query.Values(config.RedirectQuery{
RedirectURI: fmt.Sprintf("%s://%s%s", proxyCtx.Proto, proxyCtx.Host, proxyCtx.Path),
})
if err != nil {
tlog.App.Error().Err(err).Msg("Failed to encode redirect URI query")
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/error", controller.config.AppURL))
return
}
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode()))
}
func (controller *ProxyController) setHeaders(c *gin.Context, acls config.App) {
@@ -318,10 +306,7 @@ func (controller *ProxyController) setHeaders(c *gin.Context, acls config.App) {
}
func (controller *ProxyController) handleError(c *gin.Context, proxyCtx ProxyContext) {
redirectURL := fmt.Sprintf("%s/error", controller.config.AppURL)
if !controller.useBrowserResponse(proxyCtx) {
c.Header("x-tinyauth-location", redirectURL)
c.JSON(500, gin.H{
"status": 500,
"message": "Internal Server Error",
@@ -329,7 +314,7 @@ func (controller *ProxyController) handleError(c *gin.Context, proxyCtx ProxyCon
return
}
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/error", controller.config.AppURL))
}
func (controller *ProxyController) getHeader(c *gin.Context, header string) (string, bool) {

View File

@@ -6,12 +6,12 @@ import (
"testing"
"github.com/gin-gonic/gin"
"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/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/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -116,7 +116,8 @@ func TestProxyController(t *testing.T) {
assert.Equal(t, 307, recorder.Code)
location := recorder.Header().Get("Location")
assert.Equal(t, "https://tinyauth.example.com/login?redirect_uri=https%3A%2F%2Ftest.example.com%2F", location)
assert.Contains(t, location, "https://tinyauth.example.com/login?redirect_uri=")
assert.Contains(t, location, "https%3A%2F%2Ftest.example.com%2F")
},
},
{
@@ -128,8 +129,6 @@ func TestProxyController(t *testing.T) {
req.Header.Set("user-agent", browserUserAgent)
router.ServeHTTP(recorder, req)
assert.Equal(t, 401, recorder.Code)
location := recorder.Header().Get("x-tinyauth-location")
assert.Equal(t, "https://tinyauth.example.com/login?redirect_uri=https%3A%2F%2Ftest.example.com%2F", location)
},
},
{
@@ -143,7 +142,8 @@ func TestProxyController(t *testing.T) {
router.ServeHTTP(recorder, req)
assert.Equal(t, 307, recorder.Code)
location := recorder.Header().Get("Location")
assert.Equal(t, "https://tinyauth.example.com/login?redirect_uri=https%3A%2F%2Ftest.example.com%2Fhello", location)
assert.Contains(t, location, "https://tinyauth.example.com/login?redirect_uri=")
assert.Contains(t, location, "https%3A%2F%2Ftest.example.com%2Fhello")
},
},
{
@@ -159,7 +159,8 @@ func TestProxyController(t *testing.T) {
assert.Equal(t, 307, recorder.Code)
location := recorder.Header().Get("Location")
assert.Equal(t, "https://tinyauth.example.com/login?redirect_uri=https%3A%2F%2Ftest.example.com%2F", location)
assert.Contains(t, location, "https://tinyauth.example.com/login?redirect_uri=")
assert.Contains(t, location, "https%3A%2F%2Ftest.example.com%2F")
},
},
{
@@ -173,8 +174,6 @@ func TestProxyController(t *testing.T) {
req.Header.Set("user-agent", browserUserAgent)
router.ServeHTTP(recorder, req)
assert.Equal(t, 401, recorder.Code)
location := recorder.Header().Get("x-tinyauth-location")
assert.Equal(t, "https://tinyauth.example.com/login?redirect_uri=https%3A%2F%2Ftest.example.com%2F", location)
},
},
{
@@ -190,7 +189,8 @@ func TestProxyController(t *testing.T) {
router.ServeHTTP(recorder, req)
assert.Equal(t, 307, recorder.Code)
location := recorder.Header().Get("Location")
assert.Equal(t, "https://tinyauth.example.com/login?redirect_uri=https%3A%2F%2Ftest.example.com%2Fhello", location)
assert.Contains(t, location, "https://tinyauth.example.com/login?redirect_uri=")
assert.Contains(t, location, "https%3A%2F%2Ftest.example.com%2Fhello")
},
},
{

View File

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

View File

@@ -4,10 +4,10 @@ import (
"fmt"
"time"
"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/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/gin-gonic/gin"
"github.com/pquerna/otp/totp"

View File

@@ -11,12 +11,12 @@ import (
"github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp"
"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/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/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

View File

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

View File

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

View File

@@ -4,10 +4,10 @@ import (
"strings"
"time"
"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/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/gin-gonic/gin"
)

View File

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

View File

@@ -5,7 +5,7 @@ import (
"time"
"github.com/gin-gonic/gin"
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
)
// See context middleware for explanation of why we have to do this

View File

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

View File

@@ -10,10 +10,10 @@ import (
"sync"
"time"
"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/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/gin-gonic/gin"
"github.com/google/uuid"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,10 +20,10 @@ import (
"github.com/gin-gonic/gin"
"github.com/go-jose/go-jose/v4"
"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/steveiliop56/tinyauth/internal/config"
"github.com/steveiliop56/tinyauth/internal/repository"
"github.com/steveiliop56/tinyauth/internal/utils"
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
"golang.org/x/exp/slices"
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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