Implement OIDC login
This commit is contained in:
File diff suppressed because one or more lines are too long
@ -1,7 +1,7 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from './client';
|
||||
import type { GetHealthHealthGetData, GetHealthHealthGetResponses, GetAuditLogApiV1AuditGetData, GetAuditLogApiV1AuditGetResponses, GetAuditLogApiV1AuditGetErrors, LoginForAccessTokenApiV1TokenPostData, LoginForAccessTokenApiV1TokenPostResponses, LoginForAccessTokenApiV1TokenPostErrors, RefreshTokenApiV1RefreshPostData, RefreshTokenApiV1RefreshPostResponses, RefreshTokenApiV1RefreshPostErrors, ChangePasswordApiV1PasswordPostData, ChangePasswordApiV1PasswordPostResponses, ChangePasswordApiV1PasswordPostErrors, GetClientsApiV1ClientsGetData, GetClientsApiV1ClientsGetResponses, CreateClientApiV1ClientsPostData, CreateClientApiV1ClientsPostResponses, CreateClientApiV1ClientsPostErrors, GetClientsTerseApiV1ClientsTerseGetData, GetClientsTerseApiV1ClientsTerseGetResponses, QueryClientsApiV1QueryClientsGetData, QueryClientsApiV1QueryClientsGetResponses, QueryClientsApiV1QueryClientsGetErrors, DeleteClientApiV1ClientsIdDeleteData, DeleteClientApiV1ClientsIdDeleteResponses, DeleteClientApiV1ClientsIdDeleteErrors, GetClientApiV1ClientsIdGetData, GetClientApiV1ClientsIdGetResponses, GetClientApiV1ClientsIdGetErrors, UpdateClientApiV1ClientsIdPutData, UpdateClientApiV1ClientsIdPutResponses, UpdateClientApiV1ClientsIdPutErrors, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteData, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteResponses, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteErrors, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutData, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutResponses, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutErrors, UpdateClientPoliciesApiV1ClientsIdPoliciesPutData, UpdateClientPoliciesApiV1ClientsIdPoliciesPutResponses, UpdateClientPoliciesApiV1ClientsIdPoliciesPutErrors, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutData, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutResponses, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutErrors, GetSystemStatsApiV1StatsGetData, GetSystemStatsApiV1StatsGetResponses, GetSecretNamesApiV1SecretsGetData, GetSecretNamesApiV1SecretsGetResponses, AddSecretApiV1SecretsPostData, AddSecretApiV1SecretsPostResponses, AddSecretApiV1SecretsPostErrors, DeleteSecretApiV1SecretsNameDeleteData, DeleteSecretApiV1SecretsNameDeleteResponses, DeleteSecretApiV1SecretsNameDeleteErrors, GetSecretApiV1SecretsNameGetData, GetSecretApiV1SecretsNameGetResponses, GetSecretApiV1SecretsNameGetErrors, UpdateSecretApiV1SecretsNamePutData, UpdateSecretApiV1SecretsNamePutResponses, UpdateSecretApiV1SecretsNamePutErrors, GetSecretGroupsApiV1SecretsGroupsGetData, GetSecretGroupsApiV1SecretsGroupsGetResponses, GetSecretGroupsApiV1SecretsGroupsGetErrors, AddSecretGroupApiV1SecretsGroupsPostData, AddSecretGroupApiV1SecretsGroupsPostResponses, AddSecretGroupApiV1SecretsGroupsPostErrors, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteData, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteResponses, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteErrors, GetSecretGroupApiV1SecretsGroupsGroupPathGetData, GetSecretGroupApiV1SecretsGroupsGroupPathGetResponses, GetSecretGroupApiV1SecretsGroupsGroupPathGetErrors, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutData, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutResponses, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutErrors, DeleteGroupIdApiV1SecretsGroupIdDeleteData, DeleteGroupIdApiV1SecretsGroupIdDeleteResponses, DeleteGroupIdApiV1SecretsGroupIdDeleteErrors, AssignSecretGroupApiV1SecretsSetGroupPostData, AssignSecretGroupApiV1SecretsSetGroupPostResponses, AssignSecretGroupApiV1SecretsSetGroupPostErrors, MoveGroupApiV1SecretsMoveGroupGroupNamePostData, MoveGroupApiV1SecretsMoveGroupGroupNamePostResponses, MoveGroupApiV1SecretsMoveGroupGroupNamePostErrors } from './types.gen';
|
||||
import type { GetHealthHealthGetData, GetHealthHealthGetResponses, GetAuditLogApiV1AuditGetData, GetAuditLogApiV1AuditGetResponses, GetAuditLogApiV1AuditGetErrors, LoginForAccessTokenApiV1TokenPostData, LoginForAccessTokenApiV1TokenPostResponses, LoginForAccessTokenApiV1TokenPostErrors, RefreshTokenApiV1RefreshPostData, RefreshTokenApiV1RefreshPostResponses, RefreshTokenApiV1RefreshPostErrors, ChangePasswordApiV1PasswordPostData, ChangePasswordApiV1PasswordPostResponses, ChangePasswordApiV1PasswordPostErrors, StartOidcLoginApiV1OidcLoginGetData, StartOidcLoginApiV1OidcLoginGetResponses, OidcCallbackApiV1OidcCallbackGetData, OidcCallbackApiV1OidcCallbackGetResponses, GetCurrentUserApiV1UsersMeGetData, GetCurrentUserApiV1UsersMeGetResponses, GetAuthInfoApiV1OidcStatusGetData, GetAuthInfoApiV1OidcStatusGetResponses, GetClientsApiV1ClientsGetData, GetClientsApiV1ClientsGetResponses, CreateClientApiV1ClientsPostData, CreateClientApiV1ClientsPostResponses, CreateClientApiV1ClientsPostErrors, GetClientsTerseApiV1ClientsTerseGetData, GetClientsTerseApiV1ClientsTerseGetResponses, QueryClientsApiV1QueryClientsGetData, QueryClientsApiV1QueryClientsGetResponses, QueryClientsApiV1QueryClientsGetErrors, DeleteClientApiV1ClientsIdDeleteData, DeleteClientApiV1ClientsIdDeleteResponses, DeleteClientApiV1ClientsIdDeleteErrors, GetClientApiV1ClientsIdGetData, GetClientApiV1ClientsIdGetResponses, GetClientApiV1ClientsIdGetErrors, UpdateClientApiV1ClientsIdPutData, UpdateClientApiV1ClientsIdPutResponses, UpdateClientApiV1ClientsIdPutErrors, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteData, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteResponses, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteErrors, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutData, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutResponses, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutErrors, UpdateClientPoliciesApiV1ClientsIdPoliciesPutData, UpdateClientPoliciesApiV1ClientsIdPoliciesPutResponses, UpdateClientPoliciesApiV1ClientsIdPoliciesPutErrors, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutData, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutResponses, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutErrors, GetSystemStatsApiV1StatsGetData, GetSystemStatsApiV1StatsGetResponses, GetSecretNamesApiV1SecretsGetData, GetSecretNamesApiV1SecretsGetResponses, AddSecretApiV1SecretsPostData, AddSecretApiV1SecretsPostResponses, AddSecretApiV1SecretsPostErrors, DeleteSecretApiV1SecretsNameDeleteData, DeleteSecretApiV1SecretsNameDeleteResponses, DeleteSecretApiV1SecretsNameDeleteErrors, GetSecretApiV1SecretsNameGetData, GetSecretApiV1SecretsNameGetResponses, GetSecretApiV1SecretsNameGetErrors, UpdateSecretApiV1SecretsNamePutData, UpdateSecretApiV1SecretsNamePutResponses, UpdateSecretApiV1SecretsNamePutErrors, GetSecretGroupsApiV1SecretsGroupsGetData, GetSecretGroupsApiV1SecretsGroupsGetResponses, GetSecretGroupsApiV1SecretsGroupsGetErrors, AddSecretGroupApiV1SecretsGroupsPostData, AddSecretGroupApiV1SecretsGroupsPostResponses, AddSecretGroupApiV1SecretsGroupsPostErrors, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteData, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteResponses, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteErrors, GetSecretGroupApiV1SecretsGroupsGroupPathGetData, GetSecretGroupApiV1SecretsGroupsGroupPathGetResponses, GetSecretGroupApiV1SecretsGroupsGroupPathGetErrors, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutData, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutResponses, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutErrors, DeleteGroupIdApiV1SecretsGroupIdDeleteData, DeleteGroupIdApiV1SecretsGroupIdDeleteResponses, DeleteGroupIdApiV1SecretsGroupIdDeleteErrors, AssignSecretGroupApiV1SecretsSetGroupPostData, AssignSecretGroupApiV1SecretsSetGroupPostResponses, AssignSecretGroupApiV1SecretsSetGroupPostErrors, MoveGroupApiV1SecretsMoveGroupGroupNamePostData, MoveGroupApiV1SecretsMoveGroupGroupNamePostResponses, MoveGroupApiV1SecretsMoveGroupGroupNamePostErrors } from './types.gen';
|
||||
import { client as _heyApiClient } from './client.gen';
|
||||
|
||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
||||
@ -105,6 +105,60 @@ export class SshecretAdmin {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Oidc Login
|
||||
* Redirect for OIDC login.
|
||||
*/
|
||||
public static startOidcLoginApiV1OidcLoginGet<ThrowOnError extends boolean = false>(options?: Options<StartOidcLoginApiV1OidcLoginGetData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<StartOidcLoginApiV1OidcLoginGetResponses, unknown, ThrowOnError>({
|
||||
responseType: 'json',
|
||||
url: '/api/v1/oidc/login',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Oidc Callback
|
||||
* Callback for OIDC auth.
|
||||
*/
|
||||
public static oidcCallbackApiV1OidcCallbackGet<ThrowOnError extends boolean = false>(options?: Options<OidcCallbackApiV1OidcCallbackGetData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<OidcCallbackApiV1OidcCallbackGetResponses, unknown, ThrowOnError>({
|
||||
responseType: 'json',
|
||||
url: '/api/v1/oidc/callback',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Current User
|
||||
* Get information about the user currently logged in.
|
||||
*/
|
||||
public static getCurrentUserApiV1UsersMeGet<ThrowOnError extends boolean = false>(options?: Options<GetCurrentUserApiV1UsersMeGetData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<GetCurrentUserApiV1UsersMeGetResponses, unknown, ThrowOnError>({
|
||||
responseType: 'json',
|
||||
security: [
|
||||
{
|
||||
scheme: 'bearer',
|
||||
type: 'http'
|
||||
}
|
||||
],
|
||||
url: '/api/v1/users/me',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Auth Info
|
||||
* Check if OIDC login is available.
|
||||
*/
|
||||
public static getAuthInfoApiV1OidcStatusGet<ThrowOnError extends boolean = false>(options?: Options<GetAuthInfoApiV1OidcStatusGetData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<GetAuthInfoApiV1OidcStatusGetResponses, unknown, ThrowOnError>({
|
||||
responseType: 'json',
|
||||
url: '/api/v1/oidc/status',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Clients
|
||||
* Get clients.
|
||||
|
||||
@ -309,6 +309,40 @@ export type HttpValidationError = {
|
||||
detail?: Array<ValidationError>;
|
||||
};
|
||||
|
||||
/**
|
||||
* LocalUserInfo
|
||||
* Model used to present a user in the web ui.
|
||||
*/
|
||||
export type LocalUserInfo = {
|
||||
/**
|
||||
* Id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Display Name
|
||||
*/
|
||||
display_name: string;
|
||||
/**
|
||||
* Local
|
||||
*/
|
||||
local: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* LoginInfo
|
||||
* Model containing information about login providers.
|
||||
*/
|
||||
export type LoginInfo = {
|
||||
/**
|
||||
* Enabled
|
||||
*/
|
||||
enabled: boolean;
|
||||
/**
|
||||
* Oidc Provider
|
||||
*/
|
||||
oidc_provider?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Operation
|
||||
* Various operations for the audit logging module.
|
||||
@ -754,6 +788,66 @@ export type ChangePasswordApiV1PasswordPostResponses = {
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type StartOidcLoginApiV1OidcLoginGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/api/v1/oidc/login';
|
||||
};
|
||||
|
||||
export type StartOidcLoginApiV1OidcLoginGetResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type OidcCallbackApiV1OidcCallbackGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/api/v1/oidc/callback';
|
||||
};
|
||||
|
||||
export type OidcCallbackApiV1OidcCallbackGetResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type GetCurrentUserApiV1UsersMeGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/api/v1/users/me';
|
||||
};
|
||||
|
||||
export type GetCurrentUserApiV1UsersMeGetResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: LocalUserInfo;
|
||||
};
|
||||
|
||||
export type GetCurrentUserApiV1UsersMeGetResponse = GetCurrentUserApiV1UsersMeGetResponses[keyof GetCurrentUserApiV1UsersMeGetResponses];
|
||||
|
||||
export type GetAuthInfoApiV1OidcStatusGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/api/v1/oidc/status';
|
||||
};
|
||||
|
||||
export type GetAuthInfoApiV1OidcStatusGetResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: LoginInfo;
|
||||
};
|
||||
|
||||
export type GetAuthInfoApiV1OidcStatusGetResponse = GetAuthInfoApiV1OidcStatusGetResponses[keyof GetAuthInfoApiV1OidcStatusGetResponses];
|
||||
|
||||
export type GetClientsApiV1ClientsGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useAuthTokenStore } from '@/store/auth'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const auth = useAuthTokenStore()
|
||||
function getTokens() {
|
||||
const hash = window.location.hash.substring(1)
|
||||
const params = new URLSearchParams(hash)
|
||||
const accessToken = params.get('access_token')
|
||||
const refreshToken = params.get('refresh_token')
|
||||
auth.setToken(accessToken, refreshToken)
|
||||
|
||||
router.push({ name: 'dashboard' })
|
||||
}
|
||||
|
||||
onMounted(getTokens)
|
||||
</script>
|
||||
@ -18,7 +18,7 @@
|
||||
<sl-menu>
|
||||
<sl-menu-item>{{ auth.username }}</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item @click="showDrawer">Change Password</sl-menu-item>
|
||||
<sl-menu-item @click="showDrawer" v-if="!auth.oidcUser">Change Password</sl-menu-item>
|
||||
<sl-menu-item @click="logout"> Logout </sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
@ -31,7 +31,7 @@
|
||||
</Drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useAuthTokenStore } from '@/store/auth'
|
||||
@ -44,6 +44,8 @@ const router = useRouter()
|
||||
|
||||
const showPasswordDrawer = ref<boolean>(false)
|
||||
|
||||
const localUser = ref(true)
|
||||
|
||||
function logout() {
|
||||
auth.logout()
|
||||
router.push('/login')
|
||||
@ -52,6 +54,12 @@ function logout() {
|
||||
function showDrawer() {
|
||||
showPasswordDrawer.value = true
|
||||
}
|
||||
|
||||
async function getUsername() {
|
||||
await auth.getUserInfo()
|
||||
}
|
||||
|
||||
onMounted(getUsername)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -9,6 +9,7 @@ import ClientDetailPage from '@/views/clients/ClientDetailPage.vue'
|
||||
import SecretDetailView from '@/views/secrets/SecretDetailView.vue'
|
||||
import SecretGroupDetailView from '@/views/secrets/SecretGroupDetailView.vue'
|
||||
import GenericDetail from '@/components/common/GenericDetail.vue'
|
||||
import OidcCallback from '@/components/auth/OidcCallback.vue'
|
||||
import { useAuthTokenStore } from '@/store/auth'
|
||||
import { reassemblePath } from '@/api/paths'
|
||||
|
||||
@ -73,7 +74,12 @@ const routes = [
|
||||
meta: { requiresAuth: true },
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/auth_cb',
|
||||
name: 'oidcCallback',
|
||||
component: OidcCallback,
|
||||
},
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
|
||||
@ -3,6 +3,7 @@ import { defineStore } from 'pinia'
|
||||
import { client } from '@/client/client.gen'
|
||||
import { SshecretAdmin } from '@/client'
|
||||
import type { Token } from '@/client'
|
||||
import { assertSdkResponseOk } from '@/api/assertSdkResponseOk'
|
||||
|
||||
export function setAuthToken(token: string | null) {
|
||||
client.setConfig({
|
||||
@ -16,6 +17,7 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
||||
refreshToken: '' as string,
|
||||
isLoggedIn: false,
|
||||
username: '' as string,
|
||||
oidcUser: false as boolean,
|
||||
}),
|
||||
actions: {
|
||||
async login(username: string, password: string): Promise<boolean> {
|
||||
@ -38,6 +40,15 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
||||
return false
|
||||
}
|
||||
},
|
||||
setToken(accessToken: string, refreshToken: string) {
|
||||
this.accessToken = accessToken
|
||||
this.refreshToken = refreshToken
|
||||
this.isLoggedIn = true
|
||||
localStorage.setItem('accessToken', accessToken)
|
||||
localStorage.setItem('refreshToken', refreshToken)
|
||||
setAuthToken(this.accessToken)
|
||||
|
||||
},
|
||||
async refresh(): Promise<boolean> {
|
||||
try {
|
||||
console.log("Refreshing token")
|
||||
@ -57,6 +68,31 @@ export const useAuthTokenStore = defineStore('authtoken', {
|
||||
return false
|
||||
}
|
||||
},
|
||||
async getUserInfo() {
|
||||
try {
|
||||
const response = await SshecretAdmin.getCurrentUserApiV1UsersMeGet()
|
||||
const responseData = assertSdkResponseOk(response)
|
||||
this.username = responseData.display_name
|
||||
this.oidcUser = !responseData.local
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
this.logout()
|
||||
}
|
||||
},
|
||||
async getOidcProvider(): Promise<string | null> {
|
||||
try {
|
||||
const response = await SshecretAdmin.getAuthInfoApiV1OidcStatusGet()
|
||||
const responseData = assertSdkResponseOk(response)
|
||||
console.log(responseData)
|
||||
if (responseData.enabled && responseData.oidc_provider) {
|
||||
console.log('Yes')
|
||||
return responseData.oidc_provider
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
return null
|
||||
},
|
||||
loadFromStorage() {
|
||||
// Load token from user storage.
|
||||
const accessToken = localStorage.getItem('accessToken')
|
||||
|
||||
@ -1,70 +1,92 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-gray-100 flex items-center justify-center p-4">
|
||||
<div v-if="error" class="w-screen absolute top-0 left-0 z-50">
|
||||
<sl-alert variant="danger" open v-if="error">
|
||||
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||
<strong>Login failed.</strong><br />
|
||||
Please check your username and password, and try again.
|
||||
</sl-alert>
|
||||
</div>
|
||||
|
||||
<div class="max-w-md w-full bg-white rounded-xl shadow-lg p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6 text-center">Sign In</h2>
|
||||
|
||||
<form @submit.prevent="submitLogin" class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-400 mb-1">Username</label>
|
||||
<input
|
||||
v-model="username"
|
||||
type="text"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition-all"
|
||||
<sl-input
|
||||
label="Username"
|
||||
class="w-full"
|
||||
placeholder="Username"
|
||||
autocomplete="username"
|
||||
required=""
|
||||
/>
|
||||
:value="username"
|
||||
@input="username = $event.target.value"
|
||||
></sl-input>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Password</label>
|
||||
|
||||
<input
|
||||
v-model="password"
|
||||
<sl-input
|
||||
label="Password"
|
||||
type="password"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition-all"
|
||||
class="w-full"
|
||||
:value="password"
|
||||
@input="password = $event.target.value"
|
||||
placeholder="••••••••"
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
required=""
|
||||
></sl-input>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2.5 rounded-lg transition-colors"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
<sl-button type="submit" variant="primary" class="w-full"> Login </sl-button>
|
||||
</form>
|
||||
<template v-if="oidcProvider">
|
||||
<div class="w-full items-center text-center my-4 flex">
|
||||
<div class="w-full h-[0.125rem] box-border bg-gray-200 dark:bg-gray-700"></div>
|
||||
<div class="px-4 text-lg text-sm font-medium text-gray-500 dark:text-gray-400">Or</div>
|
||||
<div class="w-full h-[0.125rem] box-border bg-gray-200 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="w-full text-center my-4">
|
||||
<sl-button outline variant="neutral" :href="oidcLoginUrl">
|
||||
Sign in with {{ oidcProvider }}
|
||||
</sl-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useAuthTokenStore } from '@/store/auth'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||
import '@shoelace-style/shoelace/dist/components/alert/alert.js'
|
||||
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
const error = ref(false)
|
||||
|
||||
const auth = useAuthTokenStore()
|
||||
const router = useRouter()
|
||||
|
||||
const alerts = useAlertsStore()
|
||||
|
||||
const oidcProvider = ref<string | null>()
|
||||
|
||||
async function checkOidcProvider() {
|
||||
const provider = await auth.getOidcProvider()
|
||||
console.log(provider)
|
||||
if (provider) {
|
||||
console.log('OIDC Provider: ', provider)
|
||||
oidcProvider.value = provider
|
||||
}
|
||||
}
|
||||
|
||||
const baseURL = import.meta.env.SSHECRET_FRONTEND_API_BASE_URL
|
||||
const oidcLoginUrl = baseURL + '/api/v1/oidc/login'
|
||||
|
||||
async function submitLogin() {
|
||||
error.value = false
|
||||
const success = await auth.login(username.value, password.value)
|
||||
if (success) {
|
||||
router.push('/')
|
||||
} else {
|
||||
error.value = true
|
||||
alerts.showAlert(
|
||||
'Please check your username and password, and try again.',
|
||||
'error',
|
||||
'Login Failed',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(checkOidcProvider)
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user