mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-27 20:25:41 +00:00
feat: allow custom app and generic oauth title
This commit is contained in:
@@ -113,7 +113,9 @@ var rootCmd = &cobra.Command{
|
||||
AppURL: config.AppURL,
|
||||
CookieSecure: config.CookieSecure,
|
||||
DisableContinue: config.DisableContinue,
|
||||
CookieExpiry: config.SessionExpiry,
|
||||
SessionExpiry: config.SessionExpiry,
|
||||
Title: config.Title,
|
||||
GenericName: config.GenericName,
|
||||
}, hooks, auth, providers)
|
||||
|
||||
// Setup routes
|
||||
@@ -169,10 +171,12 @@ func init() {
|
||||
rootCmd.Flags().String("generic-auth-url", "", "Generic OAuth auth URL.")
|
||||
rootCmd.Flags().String("generic-token-url", "", "Generic OAuth token URL.")
|
||||
rootCmd.Flags().String("generic-user-url", "", "Generic OAuth user info URL.")
|
||||
rootCmd.Flags().String("generic-name", "Generic", "Generic OAuth provider name.")
|
||||
rootCmd.Flags().Bool("disable-continue", false, "Disable continue screen and redirect to app directly.")
|
||||
rootCmd.Flags().String("oauth-whitelist", "", "Comma separated list of email addresses to whitelist when using OAuth.")
|
||||
rootCmd.Flags().Int("session-expiry", 86400, "Session (cookie) expiration time in seconds.")
|
||||
rootCmd.Flags().Int("log-level", 1, "Log level.")
|
||||
rootCmd.Flags().String("app-title", "Tinyauth", "Title of the app.")
|
||||
|
||||
// Bind flags to environment
|
||||
viper.BindEnv("port", "PORT")
|
||||
@@ -199,10 +203,12 @@ func init() {
|
||||
viper.BindEnv("generic-auth-url", "GENERIC_AUTH_URL")
|
||||
viper.BindEnv("generic-token-url", "GENERIC_TOKEN_URL")
|
||||
viper.BindEnv("generic-user-url", "GENERIC_USER_URL")
|
||||
viper.BindEnv("generic-name", "GENERIC_NAME")
|
||||
viper.BindEnv("disable-continue", "DISABLE_CONTINUE")
|
||||
viper.BindEnv("oauth-whitelist", "OAUTH_WHITELIST")
|
||||
viper.BindEnv("session-expiry", "SESSION_EXPIRY")
|
||||
viper.BindEnv("log-level", "LOG_LEVEL")
|
||||
viper.BindEnv("app-title", "APP_TITLE")
|
||||
|
||||
// Bind flags to viper
|
||||
viper.BindPFlags(rootCmd.Flags())
|
||||
|
||||
@@ -84,7 +84,7 @@ func (api *API) Init() {
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: api.Config.CookieSecure,
|
||||
MaxAge: api.Config.CookieExpiry,
|
||||
MaxAge: api.Config.SessionExpiry,
|
||||
})
|
||||
|
||||
router.Use(sessions.Sessions("tinyauth", store))
|
||||
@@ -332,36 +332,45 @@ func (api *API) SetupRoutes() {
|
||||
configuredProviders = append(configuredProviders, "username")
|
||||
}
|
||||
|
||||
// We are not logged in so return unauthorized
|
||||
// Fill status struct with data from user context and api config
|
||||
status := types.Status{
|
||||
Username: userContext.Username,
|
||||
IsLoggedIn: userContext.IsLoggedIn,
|
||||
Oauth: userContext.OAuth,
|
||||
Provider: userContext.Provider,
|
||||
ConfiguredProviders: configuredProviders,
|
||||
DisableContinue: api.Config.DisableContinue,
|
||||
Title: api.Config.Title,
|
||||
GenericName: api.Config.GenericName,
|
||||
}
|
||||
|
||||
// If we are not logged in we set the status to 401 and add the WWW-Authenticate header else we set it to 200
|
||||
if !userContext.IsLoggedIn {
|
||||
log.Debug().Msg("Unauthorized")
|
||||
c.Header("WWW-Authenticate", "Basic realm=\"tinyauth\"")
|
||||
c.JSON(200, gin.H{
|
||||
"status": 200,
|
||||
"message": "Unauthorized",
|
||||
"username": "",
|
||||
"isLoggedIn": false,
|
||||
"oauth": false,
|
||||
"provider": "",
|
||||
"configuredProviders": configuredProviders,
|
||||
"disableContinue": api.Config.DisableContinue,
|
||||
})
|
||||
return
|
||||
status.Status = 401
|
||||
status.Message = "Unauthorized"
|
||||
} else {
|
||||
log.Debug().Interface("userContext", userContext).Strs("configuredProviders", configuredProviders).Bool("disableContinue", api.Config.DisableContinue).Msg("Authenticated")
|
||||
status.Status = 200
|
||||
status.Message = "Authenticated"
|
||||
}
|
||||
|
||||
log.Debug().Interface("userContext", userContext).Strs("configuredProviders", configuredProviders).Bool("disableContinue", api.Config.DisableContinue).Msg("Authenticated")
|
||||
// // Marshall status to JSON
|
||||
// statusJson, marshalErr := json.Marshal(status)
|
||||
|
||||
// We are logged in so return our user context
|
||||
c.JSON(200, gin.H{
|
||||
"status": 200,
|
||||
"message": "Authenticated",
|
||||
"username": userContext.Username,
|
||||
"isLoggedIn": userContext.IsLoggedIn,
|
||||
"oauth": userContext.OAuth,
|
||||
"provider": userContext.Provider,
|
||||
"configuredProviders": configuredProviders,
|
||||
"disableContinue": api.Config.DisableContinue,
|
||||
})
|
||||
// // Handle error
|
||||
// if marshalErr != nil {
|
||||
// log.Error().Err(marshalErr).Msg("Failed to marshal status")
|
||||
// c.JSON(500, gin.H{
|
||||
// "status": 500,
|
||||
// "message": "Internal Server Error",
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
// Return data
|
||||
c.JSON(200, status)
|
||||
})
|
||||
|
||||
api.Router.GET("/api/oauth/url/:provider", func(c *gin.Context) {
|
||||
|
||||
@@ -23,7 +23,7 @@ var apiConfig = types.APIConfig{
|
||||
Secret: "super-secret-api-thing-for-tests", // It is 32 chars long
|
||||
AppURL: "http://tinyauth.localhost",
|
||||
CookieSecure: false,
|
||||
CookieExpiry: 3600,
|
||||
SessionExpiry: 3600,
|
||||
DisableContinue: false,
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func getAPI(t *testing.T) *api.API {
|
||||
Username: user.Username,
|
||||
Password: user.Password,
|
||||
},
|
||||
}, nil, apiConfig.CookieExpiry)
|
||||
}, nil, apiConfig.SessionExpiry)
|
||||
|
||||
// Create providers service
|
||||
providers := providers.NewProviders(types.OAuthConfig{})
|
||||
|
||||
@@ -48,10 +48,12 @@ type Config struct {
|
||||
GenericAuthURL string `mapstructure:"generic-auth-url"`
|
||||
GenericTokenURL string `mapstructure:"generic-token-url"`
|
||||
GenericUserURL string `mapstructure:"generic-user-url"`
|
||||
GenericName string `mapstructure:"generic-name"`
|
||||
DisableContinue bool `mapstructure:"disable-continue"`
|
||||
OAuthWhitelist string `mapstructure:"oauth-whitelist"`
|
||||
SessionExpiry int `mapstructure:"session-expiry"`
|
||||
LogLevel int8 `mapstructure:"log-level" validate:"min=-1,max=5"`
|
||||
Title string `mapstructure:"app-title"`
|
||||
}
|
||||
|
||||
// UserContext is the context for the user
|
||||
@@ -69,8 +71,10 @@ type APIConfig struct {
|
||||
Secret string
|
||||
AppURL string
|
||||
CookieSecure bool
|
||||
CookieExpiry int
|
||||
SessionExpiry int
|
||||
DisableContinue bool
|
||||
GenericName string
|
||||
Title string
|
||||
}
|
||||
|
||||
// OAuthConfig is the configuration for the providers
|
||||
@@ -129,3 +133,17 @@ type TailscaleQuery struct {
|
||||
type Proxy struct {
|
||||
Proxy string `uri:"proxy" binding:"required"`
|
||||
}
|
||||
|
||||
// Status response
|
||||
type Status struct {
|
||||
Status int `json:"status"`
|
||||
Message string `json:"message"`
|
||||
IsLoggedIn bool `json:"isLoggedIn"`
|
||||
Username string `json:"username"`
|
||||
Provider string `json:"provider"`
|
||||
Oauth bool `json:"oauth"`
|
||||
ConfiguredProviders []string `json:"configuredProviders"`
|
||||
DisableContinue bool `json:"disableContinue"`
|
||||
Title string `json:"title"`
|
||||
GenericName string `json:"genericName"`
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export const LoginPage = () => {
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { isLoggedIn, configuredProviders } = useUserContext();
|
||||
const { isLoggedIn, configuredProviders, title, genericName } = useUserContext();
|
||||
|
||||
const oauthProviders = configuredProviders.filter(
|
||||
(value) => value !== "username",
|
||||
@@ -111,7 +111,7 @@ export const LoginPage = () => {
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Title ta="center">Tinyauth</Title>
|
||||
<Title ta="center">{title}</Title>
|
||||
<Paper shadow="md" p="xl" mt={30} radius="md" withBorder>
|
||||
{oauthProviders.length > 0 && (
|
||||
<>
|
||||
@@ -175,7 +175,7 @@ export const LoginPage = () => {
|
||||
onClick={() => loginOAuthMutation.mutate("generic")}
|
||||
loading={loginOAuthMutation.isLoading}
|
||||
>
|
||||
Generic
|
||||
{genericName}
|
||||
</Button>
|
||||
</Grid.Col>
|
||||
)}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Layout } from "../components/layouts/layout";
|
||||
import { capitalize } from "../utils/utils";
|
||||
|
||||
export const LogoutPage = () => {
|
||||
const { isLoggedIn, username, oauth, provider } = useUserContext();
|
||||
const { isLoggedIn, username, oauth, provider, genericName } = useUserContext();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return <Navigate to="/login" />;
|
||||
@@ -45,7 +45,7 @@ export const LogoutPage = () => {
|
||||
</Text>
|
||||
<Text>
|
||||
You are currently logged in as <Code>{username}</Code>
|
||||
{oauth && ` using ${capitalize(provider)} OAuth`}. Click the button
|
||||
{oauth && ` using ${capitalize(provider === "generic" ? genericName : provider)} OAuth`}. Click the button
|
||||
below to log out.
|
||||
</Text>
|
||||
<Button
|
||||
|
||||
@@ -7,6 +7,8 @@ export const userContextSchema = z.object({
|
||||
provider: z.string(),
|
||||
configuredProviders: z.array(z.string()),
|
||||
disableContinue: z.boolean(),
|
||||
title: z.string(),
|
||||
genericName: z.string(),
|
||||
});
|
||||
|
||||
export type UserContextSchemaType = z.infer<typeof userContextSchema>;
|
||||
|
||||
Reference in New Issue
Block a user