diff --git a/.changeset/serious-ads-leave.md b/.changeset/serious-ads-leave.md new file mode 100644 index 0000000000..9caf1bc461 --- /dev/null +++ b/.changeset/serious-ads-leave.md @@ -0,0 +1,22 @@ +--- +'@backstage/plugin-auth-backend-module-cloudflare-access-provider': minor +'@backstage/plugin-auth-backend-module-bitbucket-server-provider': minor +'@backstage/plugin-auth-backend-module-vmware-cloud-provider': minor +'@backstage/plugin-auth-backend-module-atlassian-provider': minor +'@backstage/plugin-auth-backend-module-bitbucket-provider': minor +'@backstage/plugin-auth-backend-module-microsoft-provider': minor +'@backstage/plugin-auth-backend-module-onelogin-provider': minor +'@backstage/plugin-auth-backend-module-pinniped-provider': minor +'@backstage/plugin-auth-backend-module-aws-alb-provider': minor +'@backstage/plugin-auth-backend-module-gcp-iap-provider': minor +'@backstage/plugin-auth-backend-module-github-provider': minor +'@backstage/plugin-auth-backend-module-gitlab-provider': minor +'@backstage/plugin-auth-backend-module-google-provider': minor +'@backstage/plugin-auth-backend-module-oauth2-provider': minor +'@backstage/plugin-auth-backend-module-auth0-provider': minor +'@backstage/plugin-auth-backend-module-oidc-provider': minor +'@backstage/plugin-auth-backend-module-okta-provider': minor +'@backstage/plugin-auth-node': minor +--- + +Added `auth.providers..sessionDuration` config for auth providers to allow the lifespan of user sessions to be configured. diff --git a/docs/auth/atlassian/provider.md b/docs/auth/atlassian/provider.md index a1009b586e..ffee3454a9 100644 --- a/docs/auth/atlassian/provider.md +++ b/docs/auth/atlassian/provider.md @@ -51,6 +51,8 @@ auth: additionalScopes: - 'read:jira-user' - 'read:jira-work' + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/atlassian/provider#resolvers for more resolvers @@ -67,6 +69,10 @@ The Atlassian provider is a structure with the following configuration keys: **NOTE:** The scopes `offline_access`, `read:jira-work`, and `read:jira-user` are provided by default. +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/auth0/provider.md b/docs/auth/auth0/provider.md index 2873a2cace..44a5bb0e43 100644 --- a/docs/auth/auth0/provider.md +++ b/docs/auth/auth0/provider.md @@ -44,6 +44,8 @@ auth: audience: ${AUTH_AUTH0_AUDIENCE} connection: ${AUTH_AUTH0_CONNECTION} connectionScope: ${AUTH_AUTH0_CONNECTION_SCOPE} + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code session: secret: ${AUTH_SESSION_SECRET} ``` @@ -66,6 +68,7 @@ Auth0 requires a session, so you need to give the session a secret key. - `audience`: The intended recipients of the token. - `connection`: Social identity provider name. To check the available social connections, please visit [Auth0 Social Connections](https://marketplace.auth0.com/features/social-connections). - `connectionScope`: Additional scopes in the interactive token request. It should always be used in combination with the `connection` parameter. +- `sessionDuration`: Lifespan of the user session. ### Resolvers diff --git a/docs/auth/aws-alb/provider.md b/docs/auth/aws-alb/provider.md index 5380877f86..5f289170d2 100644 --- a/docs/auth/aws-alb/provider.md +++ b/docs/auth/aws-alb/provider.md @@ -23,6 +23,8 @@ auth: signer: 'arn:aws:elasticloadbalancing:us-east-2:123456789012:loadbalancer/app/my-load-balancer/1234567890123456' # this is the region where your ALB instance resides region: 'us-west-2' + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/aws-alb/provider#resolvers for more resolvers @@ -31,6 +33,10 @@ auth: Ensure that you have set the signer correctly. It is also recommended that you restrict your target groups' security policy to only accept connections from that ALB. +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/bitbucket/provider.md b/docs/auth/bitbucket/provider.md index e58ad622fc..7667c7c02e 100644 --- a/docs/auth/bitbucket/provider.md +++ b/docs/auth/bitbucket/provider.md @@ -37,6 +37,8 @@ auth: development: clientId: ${AUTH_BITBUCKET_CLIENT_ID} clientSecret: ${AUTH_BITBUCKET_CLIENT_SECRET} + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/bitbucket/provider#resolvers for more resolvers @@ -49,6 +51,10 @@ The Bitbucket provider is a structure with two configuration keys: `b59241722e3c3b4816e2` - `clientSecret`: The Secret tied to the generated Key. +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/bitbucketServer/provider.md b/docs/auth/bitbucketServer/provider.md index c41457d09c..fe828a405a 100644 --- a/docs/auth/bitbucketServer/provider.md +++ b/docs/auth/bitbucketServer/provider.md @@ -34,6 +34,8 @@ auth: host: bitbucket.example.org clientId: ${AUTH_BITBUCKET_SERVER_CLIENT_ID} clientSecret: ${AUTH_BITBUCKET_SERVER_CLIENT_SECRET} + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code ``` The Bitbucket Server provider is a structure with two configuration keys: @@ -41,6 +43,10 @@ The Bitbucket Server provider is a structure with two configuration keys: - `clientId`: The client ID that was generated by Bitbucket, e.g. `b0f868455c15dcdff5c5fb5d173ae684`. - `clientSecret`: The client secret tied to the generated client ID. +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/cloudflare/provider.md b/docs/auth/cloudflare/provider.md index 224a64f056..38f9a3f06a 100644 --- a/docs/auth/cloudflare/provider.md +++ b/docs/auth/cloudflare/provider.md @@ -38,6 +38,8 @@ auth: # You can customize the authorization cookie name, by default # CF_Authorization is used authorizationCookieName: + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code # This picks what sign in resolver(s) you want to use. signIn: resolvers: @@ -47,6 +49,10 @@ auth: This config section must be in place for the provider to load at all. +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/github/provider.md b/docs/auth/github/provider.md index 3b61815017..b4168be18f 100644 --- a/docs/auth/github/provider.md +++ b/docs/auth/github/provider.md @@ -49,6 +49,8 @@ auth: clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} ## uncomment if using GitHub Enterprise # enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/github/provider#resolvers for more resolvers @@ -66,6 +68,7 @@ The GitHub provider is a structure with these configuration keys: initiating an OAuth flow, e.g. `https://your-intermediate-service.com/handler`. Only needed if Backstage is not the immediate receiver (e.g. one OAuth app for many backstage instances). +- `sessionDuration` (optional): Lifespan of the user session. - `signIn`: The configuration for the sign-in process, including the **resolvers** that should be used to match the user from the auth provider with the user entity in the Backstage catalog (typically a single resolver is sufficient). diff --git a/docs/auth/gitlab/provider.md b/docs/auth/gitlab/provider.md index 5241481463..b18b530b61 100644 --- a/docs/auth/gitlab/provider.md +++ b/docs/auth/gitlab/provider.md @@ -44,6 +44,8 @@ auth: # audience: https://gitlab.company.com ## uncomment if using a custom redirect URI # callbackUrl: https://${BASE_URL}/api/auth/gitlab/handler/frame + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/gitlab/provider#resolvers for more resolvers @@ -60,6 +62,7 @@ The GitLab provider is a structure with three configuration keys: - `callbackUrl` (optional): The URL matching the Redirect URI registered when creating your GitLab OAuth App, e.g. `https://$backstage.acme.corp/api/auth/gitlab/handler/frame` Note: Due to a peculiarity with GitLab OAuth, ensure there is no trailing `/` after 'frame' in the URL. +- `sessionDuration` (optional): Lifespan of the user session. ### Resolvers diff --git a/docs/auth/google/provider.md b/docs/auth/google/provider.md index e03985d432..9a550d5ee0 100644 --- a/docs/auth/google/provider.md +++ b/docs/auth/google/provider.md @@ -42,6 +42,8 @@ auth: development: clientId: ${AUTH_GOOGLE_CLIENT_ID} clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET} + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/google/provider#resolvers for more resolvers @@ -54,6 +56,10 @@ The Google provider is a structure with two configuration keys: `10023341500512-beui241gjwwkrdkr2eh7dprewj2pp1q.apps.googleusercontent.com` - `clientSecret`: The client secret tied to the generated client ID. +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index 74416f853e..39eed92cba 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -84,6 +84,7 @@ The Microsoft provider is a structure with three mandatory configuration keys: For more details, see [Home Realm Discovery](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/home-realm-discovery-policy) - `additionalScopes` (optional): List of scopes for the App Registration, to be requested in addition to the required ones. - `skipUserProfile` (optional): If true, skips loading the user profile even if the `User.Read` scope is present. This is a performance optimization during login and can be used with resolvers that only needs the email address in `spec.profile.email` obtained when the `email` OAuth2 scope is present. +- `sessionDuration` (optional): Lifespan of the user session. ### Resolvers diff --git a/docs/auth/oidc.md b/docs/auth/oidc.md index 6d2a937320..48f1973c2e 100644 --- a/docs/auth/oidc.md +++ b/docs/auth/oidc.md @@ -263,6 +263,7 @@ check the App Registration you created: basically the same thing. - `prompt`: Recommended to use `auto` so the browser will request login to the IDP if the user has no active session. +- `sessionDuration` (optional): Lifespan of the user session. Note that for the time being, any change in this yaml file requires a restart of the app, also you need to have the `session.secret` part to use OIDC (some other providers might diff --git a/docs/auth/okta/provider.md b/docs/auth/okta/provider.md index abc6231839..1e88aa4cf6 100644 --- a/docs/auth/okta/provider.md +++ b/docs/auth/okta/provider.md @@ -45,6 +45,8 @@ auth: audience: ${AUTH_OKTA_DOMAIN} authServerId: ${AUTH_OKTA_AUTH_SERVER_ID} # Optional idp: ${AUTH_OKTA_IDP} # Optional + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # Optional: supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code # https://developer.okta.com/docs/reference/api/oidc/#scope-dependent-claims-not-always-returned additionalScopes: ${AUTH_OKTA_ADDITIONAL_SCOPES} # Optional signIn: @@ -62,6 +64,7 @@ The values referenced are found on the Application page on your Okta site. `https://company.okta.com` - `authServerId`: The authorization server ID for the Application - `idp`: The identity provider for the application, e.g. `0oaulob4BFVa4zQvt0g3` +- `sessionDuration`: Lifespan of the user session. `additionalScopes` is an optional value, a string of space separated scopes, that will be combined with the default `scope` value of `openid profile email offline_access` to adjust the `scope` sent to Okta during OAuth. This will have an impact on [the dependent claims returned](https://developer.okta.com/docs/reference/api/oidc/#scope-dependent-claims-not-always-returned). For example, setting the `additionalScopes` value to `groups` will result in the claim returning a list of the groups that the user is a member of that also match the ID token group filter of the client app. diff --git a/docs/auth/onelogin/provider.md b/docs/auth/onelogin/provider.md index edceb1de62..d3f57f0615 100644 --- a/docs/auth/onelogin/provider.md +++ b/docs/auth/onelogin/provider.md @@ -38,6 +38,8 @@ auth: clientId: ${AUTH_ONELOGIN_CLIENT_ID} clientSecret: ${AUTH_ONELOGIN_CLIENT_SECRET} issuer: https://.onelogin.com/oidc/2 + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/onelogin/provider#resolvers for more resolvers @@ -51,6 +53,10 @@ found on the SSO tab** for the OneLogin Application: - `clientSecret`: The client secret - `issuer`: The issuer URL +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/docs/auth/vmware-cloud/provider.md b/docs/auth/vmware-cloud/provider.md index d654331178..3f747f494e 100644 --- a/docs/auth/vmware-cloud/provider.md +++ b/docs/auth/vmware-cloud/provider.md @@ -47,6 +47,8 @@ auth: development: clientId: ${APP_ID} organizationId: ${ORG_ID} + ## uncomment to set lifespan of user session + # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code signIn: resolvers: # See https://backstage.io/docs/auth/vmware-cloud/provider#resolvers for more resolvers @@ -68,6 +70,10 @@ key for signing session cookies set by Backstage. ::: +### Optional + +- `sessionDuration`: Lifespan of the user session. + ### Resolvers This provider includes several resolvers out of the box that you can use: diff --git a/plugins/auth-backend-module-atlassian-provider/config.d.ts b/plugins/auth-backend-module-atlassian-provider/config.d.ts index b1edea3d6c..f6433c123e 100644 --- a/plugins/auth-backend-module-atlassian-provider/config.d.ts +++ b/plugins/auth-backend-module-atlassian-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -38,6 +40,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index ee17153053..cc625dfe30 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -45,6 +45,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-auth0-provider/config.d.ts b/plugins/auth-backend-module-auth0-provider/config.d.ts index a0ec7d4eac..661409a592 100644 --- a/plugins/auth-backend-module-auth0-provider/config.d.ts +++ b/plugins/auth-backend-module-auth0-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -30,6 +32,7 @@ export interface Config { audience?: string; connection?: string; connectionScope?: string; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 787cce9072..2fb6370095 100644 --- a/plugins/auth-backend-module-auth0-provider/package.json +++ b/plugins/auth-backend-module-auth0-provider/package.json @@ -45,6 +45,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "@types/passport-auth0": "^1.0.5", "@types/passport-oauth2": "^1.4.15", "supertest": "^7.0.0" diff --git a/plugins/auth-backend-module-aws-alb-provider/config.d.ts b/plugins/auth-backend-module-aws-alb-provider/config.d.ts index 2e38490b28..41c84872de 100644 --- a/plugins/auth-backend-module-aws-alb-provider/config.d.ts +++ b/plugins/auth-backend-module-aws-alb-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -48,6 +50,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index 0e804631dc..5985154eb5 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -48,6 +48,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/types": "workspace:^", "express": "^4.18.2", "msw": "^2.0.8" } diff --git a/plugins/auth-backend-module-bitbucket-provider/config.d.ts b/plugins/auth-backend-module-bitbucket-provider/config.d.ts index 552a66d700..f3d82608bd 100644 --- a/plugins/auth-backend-module-bitbucket-provider/config.d.ts +++ b/plugins/auth-backend-module-bitbucket-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -36,6 +38,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 9a4f801efa..d8f137d1d0 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -45,6 +45,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-bitbucket-server-provider/config.d.ts b/plugins/auth-backend-module-bitbucket-server-provider/config.d.ts index ee924f47f0..8e63581625 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/config.d.ts +++ b/plugins/auth-backend-module-bitbucket-server-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -27,6 +29,7 @@ export interface Config { clientSecret: string; host: string; callbackUrl?: string; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-bitbucket-server-provider/package.json b/plugins/auth-backend-module-bitbucket-server-provider/package.json index 6b3a1f95f0..c546d05be9 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-server-provider/package.json @@ -44,6 +44,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "@types/passport-oauth2": "^1.4.15", "supertest": "^7.0.0" }, diff --git a/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts b/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts index b73c8d87a5..39a4ca3eb6 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts +++ b/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts @@ -43,6 +43,7 @@ export interface Config { * The backstage token expiration. */ backstageTokenExpiration?: HumanDuration | string; + sessionDuration?: HumanDuration | string; }; }; } diff --git a/plugins/auth-backend-module-gcp-iap-provider/config.d.ts b/plugins/auth-backend-module-gcp-iap-provider/config.d.ts index d4fe015b7c..d99d890b50 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/config.d.ts +++ b/plugins/auth-backend-module-gcp-iap-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -43,6 +45,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-github-provider/config.d.ts b/plugins/auth-backend-module-github-provider/config.d.ts index b1bc0dc477..69abfa0d12 100644 --- a/plugins/auth-backend-module-github-provider/config.d.ts +++ b/plugins/auth-backend-module-github-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -38,6 +40,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 5a78c46541..ecf8fced7c 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -43,6 +43,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-gitlab-provider/config.d.ts b/plugins/auth-backend-module-gitlab-provider/config.d.ts index cbb9f01e02..8d47421255 100644 --- a/plugins/auth-backend-module-gitlab-provider/config.d.ts +++ b/plugins/auth-backend-module-gitlab-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -38,6 +40,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index ec0a967264..4f26d564ee 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -45,6 +45,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-google-provider/config.d.ts b/plugins/auth-backend-module-google-provider/config.d.ts index 1571c06deb..ec3cd92b31 100644 --- a/plugins/auth-backend-module-google-provider/config.d.ts +++ b/plugins/auth-backend-module-google-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { /** Configuration options for the auth plugin */ auth?: { @@ -38,6 +40,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 4c0313ba62..b88106229a 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -47,6 +47,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "@types/passport-google-oauth20": "^2.0.3", "supertest": "^7.0.0" }, diff --git a/plugins/auth-backend-module-microsoft-provider/config.d.ts b/plugins/auth-backend-module-microsoft-provider/config.d.ts index 070b6300f7..d69637e7a2 100644 --- a/plugins/auth-backend-module-microsoft-provider/config.d.ts +++ b/plugins/auth-backend-module-microsoft-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -40,6 +42,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index a2d45c1ddd..028fea47ed 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -46,6 +46,7 @@ "@backstage/cli": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "@types/passport-microsoft": "^1.0.0", "msw": "^1.0.0", "supertest": "^7.0.0" diff --git a/plugins/auth-backend-module-oauth2-provider/config.d.ts b/plugins/auth-backend-module-oauth2-provider/config.d.ts index 5cee3a5407..ba047e3340 100644 --- a/plugins/auth-backend-module-oauth2-provider/config.d.ts +++ b/plugins/auth-backend-module-oauth2-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -42,6 +44,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index e9c236ee5d..6da2bafc97 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -44,6 +44,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-oidc-provider/config.d.ts b/plugins/auth-backend-module-oidc-provider/config.d.ts index d59c40697a..409c658c23 100644 --- a/plugins/auth-backend-module-oidc-provider/config.d.ts +++ b/plugins/auth-backend-module-oidc-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -40,6 +42,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index f52eddcdcd..b7897f521e 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -46,6 +46,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/types": "workspace:^", "cookie-parser": "^1.4.6", "express-promise-router": "^4.1.1", "express-session": "^1.17.3", diff --git a/plugins/auth-backend-module-okta-provider/config.d.ts b/plugins/auth-backend-module-okta-provider/config.d.ts index d2b0c4aa02..3f27e805ec 100644 --- a/plugins/auth-backend-module-okta-provider/config.d.ts +++ b/plugins/auth-backend-module-okta-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -40,6 +42,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index fe1dd2e32e..26e45a0944 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -45,6 +45,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-onelogin-provider/config.d.ts b/plugins/auth-backend-module-onelogin-provider/config.d.ts index da7c312dd3..58f471bafb 100644 --- a/plugins/auth-backend-module-onelogin-provider/config.d.ts +++ b/plugins/auth-backend-module-onelogin-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -37,6 +39,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index 90e0a745a4..2c1e7de9f7 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -45,6 +45,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index c20faccc48..577bc0ce90 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -36,6 +36,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", + "@backstage/types": "workspace:^", "luxon": "^3.4.3", "openid-client": "^5.4.3" }, diff --git a/plugins/auth-backend-module-pinniped-provider/src/config.d.ts b/plugins/auth-backend-module-pinniped-provider/src/config.d.ts index 50685abfb0..242de7b2b9 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/config.d.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { /** Configuration options for the auth plugin */ auth?: { @@ -27,6 +29,7 @@ export interface Config { */ clientSecret: string; scope?: string; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts b/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts index 67db735713..9886d69a41 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts +++ b/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { HumanDuration } from '@backstage/types'; + export interface Config { auth?: { providers?: { @@ -34,6 +36,7 @@ export interface Config { | { resolver: 'emailMatchingUserEntityProfileEmail' } >; }; + sessionDuration?: HumanDuration | string; }; }; }; diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index e081c896ac..dd6ce0941b 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -47,6 +47,7 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/types": "workspace:^", "msw": "^2.0.8", "supertest": "^7.0.0" } diff --git a/plugins/auth-node/src/oauth/OAuthCookieManager.ts b/plugins/auth-node/src/oauth/OAuthCookieManager.ts index d594d7e78b..8d1c4787cc 100644 --- a/plugins/auth-node/src/oauth/OAuthCookieManager.ts +++ b/plugins/auth-node/src/oauth/OAuthCookieManager.ts @@ -16,6 +16,7 @@ import { CookieOptions, Request, Response } from 'express'; import { CookieConfigurer } from '../types'; +import { HumanDuration, durationToMilliseconds } from '@backstage/types'; const THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000; const TEN_MINUTES_MS = 600 * 1000; @@ -55,6 +56,7 @@ export class OAuthCookieManager { private readonly nonceCookie: string; private readonly refreshTokenCookie: string; private readonly grantedScopeCookie: string; + private readonly maxAge: number; constructor( private readonly options: { @@ -63,6 +65,7 @@ export class OAuthCookieManager { baseUrl: string; callbackUrl: string; cookieConfigurer?: CookieConfigurer; + sessionDuration?: HumanDuration; }, ) { this.cookieConfigurer = options.cookieConfigurer ?? defaultCookieConfigurer; @@ -70,6 +73,9 @@ export class OAuthCookieManager { this.nonceCookie = `${options.providerId}-nonce`; this.refreshTokenCookie = `${options.providerId}-refresh-token`; this.grantedScopeCookie = `${options.providerId}-granted-scope`; + this.maxAge = options.sessionDuration + ? durationToMilliseconds(options.sessionDuration) + : THOUSAND_DAYS_MS; } private getConfig(origin?: string, pathSuffix: string = '') { @@ -103,7 +109,7 @@ export class OAuthCookieManager { res, this.refreshTokenCookie, refreshToken, - THOUSAND_DAYS_MS, + this.maxAge, origin, ); } @@ -117,13 +123,7 @@ export class OAuthCookieManager { } setGrantedScopes(res: Response, scope: string, origin?: string): void { - this.setCookie( - res, - this.grantedScopeCookie, - scope, - THOUSAND_DAYS_MS, - origin, - ); + this.setCookie(res, this.grantedScopeCookie, scope, this.maxAge, origin); } getNonce(req: Request): string | undefined { diff --git a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts index 46fa058b47..5bc9fa2551 100644 --- a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts +++ b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts @@ -813,6 +813,75 @@ describe('createOAuthRouteHandlers', () => { }, }); }); + + it('should set sessionDuration to configured value', async () => { + const baseConfigWithSessionDuration = { + ...baseConfig, + config: new ConfigReader({ + sessionDuration: { days: 7 }, + }), + }; + + const agent = request.agent( + wrapInApp(createOAuthRouteHandlers(baseConfigWithSessionDuration)), + ); + + agent.jar.setCookie( + 'my-provider-refresh-token=refresh-token', + '127.0.0.1', + '/my-provider', + ); + + mockAuthenticator.refresh.mockImplementation(async ({ scope }) => ({ + fullProfile: { id: 'id' } as PassportProfile, + session: { ...mockSession, scope, refreshToken: 'new-refresh-token' }, + })); + + const res = await agent + .post('/my-provider/refresh') + .set('X-Requested-With', 'XMLHttpRequest'); + + expect(res.status).toBe(200); + const expectedExpirationDate = Date.now() + 7 * 24 * 60 * 60 * 1000; + const cookie = getRefreshTokenCookie(agent); + expect(cookie.expiration_date).toBeGreaterThanOrEqual( + expectedExpirationDate - 1000, + ); + expect(cookie.expiration_date).toBeLessThanOrEqual( + expectedExpirationDate + 1000, + ); + }); + + it('should set sessionDuration to default of 1000 days when not configured', async () => { + const agent = request.agent( + wrapInApp(createOAuthRouteHandlers(baseConfig)), + ); + + agent.jar.setCookie( + 'my-provider-refresh-token=refresh-token', + '127.0.0.1', + '/my-provider', + ); + + mockAuthenticator.refresh.mockImplementation(async ({ scope }) => ({ + fullProfile: { id: 'id' } as PassportProfile, + session: { ...mockSession, scope, refreshToken: 'new-refresh-token' }, + })); + + const res = await agent + .post('/my-provider/refresh') + .set('X-Requested-With', 'XMLHttpRequest'); + + expect(res.status).toBe(200); + const expectedExpirationDate = Date.now() + 1000 * 24 * 60 * 60 * 1000; + const cookie = getRefreshTokenCookie(agent); + expect(cookie.expiration_date).toBeGreaterThanOrEqual( + expectedExpirationDate - 1000, + ); + expect(cookie.expiration_date).toBeLessThanOrEqual( + expectedExpirationDate + 1000, + ); + }); }); describe('logout', () => { diff --git a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts index 53ae4101d3..72f45d8ab1 100644 --- a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts +++ b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts @@ -40,7 +40,7 @@ import { SignInResolver, } from '../types'; import { OAuthAuthenticator, OAuthAuthenticatorResult } from './types'; -import { Config } from '@backstage/config'; +import { Config, readDurationFromConfig } from '@backstage/config'; import { CookieScopeManager } from './CookieScopeManager'; /** @public */ @@ -99,6 +99,9 @@ export function createOAuthRouteHandlers( const callbackUrl = config.getOptionalString('callbackUrl') ?? `${baseUrl}/${providerId}/handler/frame`; + const sessionDuration = config.has('sessionDuration') + ? readDurationFromConfig(config, { key: 'sessionDuration' }) + : undefined; const stateTransform = options.stateTransform ?? (state => ({ state })); const profileTransform = @@ -110,6 +113,7 @@ export function createOAuthRouteHandlers( defaultAppOrigin, providerId, cookieConfigurer, + sessionDuration, }); const scopeManager = CookieScopeManager.create({ diff --git a/yarn.lock b/yarn.lock index ab8676ace9..f5d1f71c42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4960,6 +4960,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" express: ^4.18.2 passport: ^0.7.0 passport-atlassian-oauth2: ^2.1.0 @@ -4977,6 +4978,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" "@types/passport-auth0": ^1.0.5 "@types/passport-oauth2": ^1.4.15 express: ^4.17.1 @@ -4997,6 +4999,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" express: ^4.18.2 jose: ^5.0.0 msw: ^2.0.8 @@ -5032,6 +5035,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" express: ^4.18.2 passport: ^0.7.0 passport-bitbucket-oauth2: ^0.1.2 @@ -5049,6 +5053,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" "@types/passport-oauth2": ^1.4.15 passport: ^0.7.0 passport-oauth2: ^1.6.1 @@ -5102,6 +5107,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" passport-github2: ^0.1.12 supertest: ^7.0.0 languageName: unknown @@ -5117,6 +5123,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" express: ^4.18.2 passport: ^0.7.0 passport-gitlab2: ^5.0.0 @@ -5133,6 +5140,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" "@types/passport-google-oauth20": ^2.0.3 google-auth-library: ^9.0.0 passport-google-oauth20: ^2.0.0 @@ -5167,6 +5175,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" "@types/passport-microsoft": ^1.0.0 express: ^4.18.2 jose: ^5.0.0 @@ -5186,6 +5195,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" passport: ^0.7.0 passport-oauth2: ^1.6.1 supertest: ^7.0.0 @@ -5216,6 +5226,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" cookie-parser: ^1.4.6 express: ^4.18.2 express-promise-router: ^4.1.1 @@ -5238,6 +5249,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" "@davidzemon/passport-okta-oauth": ^0.0.5 express: ^4.18.2 passport: ^0.7.0 @@ -5255,6 +5267,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" express: ^4.18.2 passport: ^0.7.0 passport-onelogin-oauth: ^0.0.1 @@ -5273,6 +5286,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" cookie-parser: ^1.4.6 express: ^4.18.2 express-session: ^1.17.3 @@ -5298,6 +5312,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/types": "workspace:^" "@types/passport-oauth2": ^1.4.15 jose: ^5.0.0 msw: ^2.0.8