mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-04-12 16:57:55 +00:00
Compare commits
3 Commits
fix/oidc-c
...
scottmcken
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40bb8b4472 | ||
|
|
e7b44ee54e | ||
|
|
ea21cbdcd4 |
@@ -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=="],
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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 };
|
|
||||||
@@ -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)}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "oidc_tokens" DROP COLUMN "code_hash";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "oidc_tokens" ADD COLUMN "code_hash" TEXT DEFAULT "";
|
|
||||||
@@ -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{
|
||||||
|
|||||||
@@ -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{})
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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" = ?;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user