diff --git a/web-vault-sso.patch b/web-vault-sso.patch
new file mode 100644
index 00000000..dde307ad
--- /dev/null
+++ b/web-vault-sso.patch
@@ -0,0 +1,570 @@
+Submodule jslib contains modified content
+diff --git a/jslib/angular/src/components/register.component.ts b/jslib/angular/src/components/register.component.ts
+index 53ec3c8..7b49db1 100644
+--- a/jslib/angular/src/components/register.component.ts
++++ b/jslib/angular/src/components/register.component.ts
+@@ -24,7 +24,7 @@ export class RegisterComponent {
+ formPromise: Promise;
+ masterPasswordScore: number;
+ referenceData: ReferenceEventRequest;
+- showTerms = true;
++ showTerms = false;
+ acceptPolicies: boolean = false;
+
+ protected successRoute = 'login';
+@@ -35,7 +35,7 @@ export class RegisterComponent {
+ protected apiService: ApiService, protected stateService: StateService,
+ protected platformUtilsService: PlatformUtilsService,
+ protected passwordGenerationService: PasswordGenerationService) {
+- this.showTerms = !platformUtilsService.isSelfHost();
++ this.showTerms = false;
+ }
+
+ get masterPasswordScoreWidth() {
+@@ -69,6 +69,12 @@ export class RegisterComponent {
+ }
+
+ async submit() {
++ if (typeof crypto.subtle === 'undefined') {
++ this.platformUtilsService.showToast('error', "This browser requires HTTPS to use the web vault",
++ "Check the Vaultwarden wiki for details on how to enable it");
++ return;
++ }
++
+ if (!this.acceptPolicies && this.showTerms) {
+ this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
+ this.i18nService.t('acceptPoliciesError'));
+diff --git a/jslib/angular/src/components/sso.component.ts b/jslib/angular/src/components/sso.component.ts
+index d4512a1..ad57f69 100644
+--- a/jslib/angular/src/components/sso.component.ts
++++ b/jslib/angular/src/components/sso.component.ts
+@@ -19,6 +19,8 @@ import { Utils } from 'jslib-common/misc/utils';
+
+ import { AuthResult } from 'jslib-common/models/domain/authResult';
+
++import { switchMap } from 'rxjs/operators';
++
+ @Directive()
+ export class SsoComponent {
+ identifier: string;
+@@ -48,13 +50,19 @@ export class SsoComponent {
+
+ async ngOnInit() {
+ const queryParamsSub = this.route.queryParams.subscribe(async qParams => {
+- if (qParams.code != null && qParams.state != null) {
++ // I have no idea why the qParams is empty here - I've hacked in an alternative very messily, but it works.
++ const workingParams = (new URL(window.location.href)).searchParams;
++ const workingSwap = {
++ code: workingParams.get('code'),
++ state: workingParams.get('state'),
++ };
++ if (workingSwap.code != null && workingSwap.state != null) {
+ const codeVerifier = await this.storageService.get(ConstantsService.ssoCodeVerifierKey);
+ const state = await this.storageService.get(ConstantsService.ssoStateKey);
+ await this.storageService.remove(ConstantsService.ssoCodeVerifierKey);
+ await this.storageService.remove(ConstantsService.ssoStateKey);
+- if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) {
+- await this.logIn(qParams.code, codeVerifier, this.getOrgIdentiferFromState(qParams.state));
++ if (workingSwap.code != null && codeVerifier != null && state != null && this.checkState(state, workingSwap.state)) {
++ await this.logIn(workingSwap.code, codeVerifier, this.getOrgIdentiferFromState(workingSwap.state));
+ }
+ } else if (qParams.clientId != null && qParams.redirectUri != null && qParams.state != null &&
+ qParams.codeChallenge != null) {
+@@ -122,7 +130,7 @@ export class SsoComponent {
+ let authorizeUrl = this.apiService.identityBaseUrl + '/connect/authorize?' +
+ 'client_id=' + this.clientId + '&redirect_uri=' + encodeURIComponent(this.redirectUri) + '&' +
+ 'response_type=code&scope=api offline_access&' +
+- 'state=' + state + '&code_challenge=' + codeChallenge + '&' +
++ 'state=' + encodeURIComponent(state) + '&code_challenge=' + codeChallenge + '&' +
+ 'code_challenge_method=S256&response_mode=query&' +
+ 'domain_hint=' + encodeURIComponent(this.identifier);
+
+@@ -137,7 +145,7 @@ export class SsoComponent {
+ private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
+ this.loggingIn = true;
+ try {
+- this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri);
++ this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri, orgIdFromState);
+ const response = await this.formPromise;
+ if (response.twoFactor) {
+ if (this.onSuccessfulLoginTwoFactorNavigate != null) {
+diff --git a/jslib/common/src/abstractions/api.service.ts b/jslib/common/src/abstractions/api.service.ts
+index 67131df..e75a874 100644
+--- a/jslib/common/src/abstractions/api.service.ts
++++ b/jslib/common/src/abstractions/api.service.ts
+@@ -33,6 +33,7 @@ import { KeysRequest } from '../models/request/keysRequest';
+ import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
+ import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
+ import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
++import { OrganizationSsoUpdateRequest } from '../models/request/organizationSsoUpdateRequest';
+ import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
+ import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
+ import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
+@@ -360,6 +361,7 @@ export abstract class ApiService {
+ getOrganizationTaxInfo: (id: string) => Promise;
+ postOrganization: (request: OrganizationCreateRequest) => Promise;
+ putOrganization: (id: string, request: OrganizationUpdateRequest) => Promise;
++ putOrganizationSso: (id: string, request: OrganizationSsoUpdateRequest) => Promise;
+ putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise;
+ postLeaveOrganization: (id: string) => Promise;
+ postOrganizationLicense: (data: FormData) => Promise;
+diff --git a/jslib/common/src/abstractions/auth.service.ts b/jslib/common/src/abstractions/auth.service.ts
+index ac7ef04..5b1b774 100644
+--- a/jslib/common/src/abstractions/auth.service.ts
++++ b/jslib/common/src/abstractions/auth.service.ts
+@@ -15,7 +15,7 @@ export abstract class AuthService {
+ selectedTwoFactorProviderType: TwoFactorProviderType;
+
+ logIn: (email: string, masterPassword: string) => Promise;
+- logInSso: (code: string, codeVerifier: string, redirectUrl: string) => Promise;
++ logInSso: (code: string, codeVerifier: string, redirectUrl: string, orgIdentifier: string) => Promise;
+ logInApiKey: (clientId: string, clientSecret: string) => Promise;
+ logInTwoFactor: (twoFactorProvider: TwoFactorProviderType, twoFactorToken: string,
+ remember?: boolean) => Promise;
+diff --git a/jslib/common/src/models/request/tokenRequest.ts b/jslib/common/src/models/request/tokenRequest.ts
+index 7578012..964364f 100644
+--- a/jslib/common/src/models/request/tokenRequest.ts
++++ b/jslib/common/src/models/request/tokenRequest.ts
+@@ -14,9 +14,10 @@ export class TokenRequest {
+ provider: TwoFactorProviderType;
+ remember: boolean;
+ device?: DeviceRequest;
++ orgIdentifier?: string;
+
+ constructor(credentials: string[], codes: string[], clientIdClientSecret: string[], provider: TwoFactorProviderType,
+- token: string, remember: boolean, device?: DeviceRequest) {
++ token: string, remember: boolean, device?: DeviceRequest, orgIdentifier?: string) {
+ if (credentials != null && credentials.length > 1) {
+ this.email = credentials[0];
+ this.masterPasswordHash = credentials[1];
+@@ -28,6 +29,9 @@ export class TokenRequest {
+ this.clientId = clientIdClientSecret[0];
+ this.clientSecret = clientIdClientSecret[1];
+ }
++ if (orgIdentifier && orgIdentifier !== '') {
++ this.orgIdentifier = orgIdentifier;
++ }
+ this.token = token;
+ this.provider = provider;
+ this.remember = remember;
+@@ -53,6 +57,7 @@ export class TokenRequest {
+ obj.code = this.code;
+ obj.code_verifier = this.codeVerifier;
+ obj.redirect_uri = this.redirectUri;
++ obj.org_identifier = this.orgIdentifier;
+ } else {
+ throw new Error('must provide credentials or codes');
+ }
+diff --git a/jslib/common/src/models/response/organizationResponse.ts b/jslib/common/src/models/response/organizationResponse.ts
+index 21d8d43..896b7a6 100644
+--- a/jslib/common/src/models/response/organizationResponse.ts
++++ b/jslib/common/src/models/response/organizationResponse.ts
+@@ -27,6 +27,12 @@ export class OrganizationResponse extends BaseResponse {
+ useApi: boolean;
+ useResetPassword: boolean;
+ hasPublicAndPrivateKeys: boolean;
++ useSso: boolean;
++ callbackPath: string;
++ signedOutCallbackPath: string;
++ authority: string;
++ clientId: string;
++ clientSecret: string;
+
+ constructor(response: any) {
+ super(response);
+@@ -54,5 +60,11 @@ export class OrganizationResponse extends BaseResponse {
+ this.useApi = this.getResponseProperty('UseApi');
+ this.useResetPassword = this.getResponseProperty('UseResetPassword');
+ this.hasPublicAndPrivateKeys = this.getResponseProperty('HasPublicAndPrivateKeys');
++ this.useSso = this.getResponseProperty('UseSso');
++ this.callbackPath = this.getResponseProperty('CallbackPath');
++ this.signedOutCallbackPath = this.getResponseProperty('SignedOutCallbackPath');
++ this.authority = this.getResponseProperty('Authority');
++ this.clientId = this.getResponseProperty('ClientId');
++ this.clientSecret = this.getResponseProperty('ClientSecret');
+ }
+ }
+diff --git a/jslib/common/src/services/api.service.ts b/jslib/common/src/services/api.service.ts
+index 51c1c14..1a5b088 100644
+--- a/jslib/common/src/services/api.service.ts
++++ b/jslib/common/src/services/api.service.ts
+@@ -37,6 +37,7 @@ import { KeysRequest } from '../models/request/keysRequest';
+ import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
+ import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
+ import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
++import { OrganizationSsoUpdateRequest } from '../models/request/organizationSsoUpdateRequest';
+ import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
+ import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
+ import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
+@@ -1158,6 +1159,11 @@ export class ApiService implements ApiServiceAbstraction {
+ return new OrganizationResponse(r);
+ }
+
++ async putOrganizationSso(id: string, request: OrganizationSsoUpdateRequest): Promise {
++ const r = await this.send('PUT', '/organizations/' + id + '/sso', request, true, false);
++ return new OrganizationResponse(r);
++ }
++
+ async putOrganizationTaxInfo(id: string, request: OrganizationTaxInfoUpdateRequest): Promise {
+ return this.send('PUT', '/organizations/' + id + '/tax', request, true, false);
+ }
+diff --git a/jslib/common/src/services/auth.service.ts b/jslib/common/src/services/auth.service.ts
+index 6536a94..6f4899c 100644
+--- a/jslib/common/src/services/auth.service.ts
++++ b/jslib/common/src/services/auth.service.ts
+@@ -130,10 +130,10 @@ export class AuthService implements AuthServiceAbstraction {
+ key, null, null, null);
+ }
+
+- async logInSso(code: string, codeVerifier: string, redirectUrl: string): Promise {
++ async logInSso(code: string, codeVerifier: string, redirectUrl: string, orgIdentifier: string): Promise {
+ this.selectedTwoFactorProviderType = null;
+ return await this.logInHelper(null, null, null, code, codeVerifier, redirectUrl, null, null,
+- null, null, null, null);
++ null, null, null, null, orgIdentifier);
+ }
+
+ async logInApiKey(clientId: string, clientSecret: string): Promise {
+@@ -272,7 +272,7 @@ export class AuthService implements AuthServiceAbstraction {
+
+ private async logInHelper(email: string, hashedPassword: string, localHashedPassword: string, code: string,
+ codeVerifier: string, redirectUrl: string, clientId: string, clientSecret: string, key: SymmetricCryptoKey,
+- twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean): Promise {
++ twoFactorProvider?: TwoFactorProviderType, twoFactorToken?: string, remember?: boolean, orgIdentifier?: string): Promise {
+ const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
+ const appId = await this.appIdService.getAppId();
+ const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
+@@ -300,13 +300,13 @@ export class AuthService implements AuthServiceAbstraction {
+ let request: TokenRequest;
+ if (twoFactorToken != null && twoFactorProvider != null) {
+ request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, twoFactorProvider,
+- twoFactorToken, remember, deviceRequest);
++ twoFactorToken, remember, deviceRequest, orgIdentifier);
+ } else if (storedTwoFactorToken != null) {
+ request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, TwoFactorProviderType.Remember,
+- storedTwoFactorToken, false, deviceRequest);
++ storedTwoFactorToken, false, deviceRequest, orgIdentifier);
+ } else {
+ request = new TokenRequest(emailPassword, codeCodeVerifier, clientIdClientSecret, null,
+- null, false, deviceRequest);
++ null, false, deviceRequest, orgIdentifier);
+ }
+
+ const response = await this.apiService.postIdentityToken(request);
+diff --git a/src/404.html b/src/404.html
+index eba36375..cb8883ec 100644
+--- a/src/404.html
++++ b/src/404.html
+@@ -41,10 +41,10 @@
+
+
+ You can return to the web vault, check our status page
+- or contact us.
++ or contact us.
+
+
+