diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index ccaeb2828b..3c8054d995 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -31,7 +31,10 @@ const app = createApp({
plugins: Object.values(plugins),
components: {
SignInPage: props => (
-
+
),
},
});
diff --git a/packages/core/src/layout/SignInPage/gitlabProvider.tsx b/packages/core/src/layout/SignInPage/gitlabProvider.tsx
new file mode 100644
index 0000000000..5e417cb32d
--- /dev/null
+++ b/packages/core/src/layout/SignInPage/gitlabProvider.tsx
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { Grid, Typography, Button } from '@material-ui/core';
+import { InfoCard } from '../InfoCard/InfoCard';
+import { ProviderComponent, ProviderLoader, SignInProvider } from './types';
+import { useApi, gitlabAuthApiRef, errorApiRef } from '@backstage/core-api';
+
+const Component: ProviderComponent = ({ onResult }) => {
+ const gitlabAuthApi = useApi(gitlabAuthApiRef);
+ const errorApi = useApi(errorApiRef);
+
+ const handleLogin = async () => {
+ try {
+ const identity = await gitlabAuthApi.getBackstageIdentity({
+ instantPopup: true,
+ });
+
+ const profile = await gitlabAuthApi.getProfile();
+ onResult({
+ userId: identity!.id,
+ profile: profile!,
+ getIdToken: () =>
+ gitlabAuthApi.getBackstageIdentity().then(i => i!.idToken),
+ logout: async () => {
+ await gitlabAuthApi.logout();
+ },
+ });
+ } catch (error) {
+ errorApi.post(error);
+ }
+ };
+
+ return (
+
+
+ Sign In
+
+ }
+ >
+ Sign In using Gitlab
+
+
+ );
+};
+
+const loader: ProviderLoader = async apis => {
+ const gitlabAuthApi = apis.get(gitlabAuthApiRef)!;
+
+ const identity = await gitlabAuthApi.getBackstageIdentity({
+ optional: true,
+ });
+
+ if (!identity) {
+ return undefined;
+ }
+
+ const profile = await gitlabAuthApi.getProfile();
+
+ return {
+ userId: identity.id,
+ profile: profile!,
+ getIdToken: () =>
+ gitlabAuthApi.getBackstageIdentity().then(i => i!.idToken),
+ logout: async () => {
+ await gitlabAuthApi.logout();
+ },
+ };
+};
+
+export const gitlabProvider: SignInProvider = { Component, loader };
diff --git a/packages/core/src/layout/SignInPage/providers.tsx b/packages/core/src/layout/SignInPage/providers.tsx
index a195b2042a..53d6b75eac 100644
--- a/packages/core/src/layout/SignInPage/providers.tsx
+++ b/packages/core/src/layout/SignInPage/providers.tsx
@@ -18,6 +18,7 @@ import React, { useLayoutEffect, useState, useMemo, useCallback } from 'react';
import { guestProvider } from './guestProvider';
import { googleProvider } from './googleProvider';
import { customProvider } from './customProvider';
+import { gitlabProvider } from './gitlabProvider';
import { oktaProvider } from './oktaProvider';
import {
SignInPageProps,
@@ -31,11 +32,17 @@ import { SignInProvider } from './types';
const PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider';
// Separate list here to avoid exporting internal types
-export type SignInProviderId = 'guest' | 'google' | 'custom' | 'okta';
+export type SignInProviderId =
+ | 'guest'
+ | 'google'
+ | 'gitlab'
+ | 'custom'
+ | 'okta';
const signInProviders: { [id in SignInProviderId]: SignInProvider } = {
guest: guestProvider,
google: googleProvider,
+ gitlab: gitlabProvider,
custom: customProvider,
okta: oktaProvider,
};
diff --git a/plugins/auth-backend/src/providers/gitlab/provider.test.ts b/plugins/auth-backend/src/providers/gitlab/provider.test.ts
index 5eec6c47f9..d4d1de17ec 100644
--- a/plugins/auth-backend/src/providers/gitlab/provider.test.ts
+++ b/plugins/auth-backend/src/providers/gitlab/provider.test.ts
@@ -41,6 +41,9 @@ describe('GitlabAuthProvider', () => {
},
},
expect: {
+ backstageIdentity: {
+ id: 'jimmymarkum',
+ },
providerInfo: {
accessToken: '19xasczxcm9n7gacn9jdgm19me',
expiresInSeconds: 100,
@@ -74,6 +77,9 @@ describe('GitlabAuthProvider', () => {
},
},
expect: {
+ backstageIdentity: {
+ id: 'daveboyle',
+ },
providerInfo: {
accessToken:
'ajakljsdoiahoawxbrouawucmbawe.awkxjemaneasdxwe.sodijxqeqwexeqwxe',
diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts
index 890fbb3531..950c414750 100644
--- a/plugins/auth-backend/src/providers/gitlab/provider.ts
+++ b/plugins/auth-backend/src/providers/gitlab/provider.ts
@@ -78,6 +78,14 @@ export class GitlabAuthProvider implements OAuthProviderHandlers {
idToken: params.id_token,
};
+ // gitlab provides an id numeric value (123)
+ // as a fallback
+ let id = passportProfile!.id;
+
+ if (profile.email) {
+ id = profile.email.split('@')[0];
+ }
+
if (params.expires_in) {
providerInfo.expiresInSeconds = params.expires_in;
}
@@ -87,6 +95,9 @@ export class GitlabAuthProvider implements OAuthProviderHandlers {
return {
providerInfo,
profile,
+ backstageIdentity: {
+ id,
+ },
};
}