descope 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yaml +54 -0
  3. data/.gitignore +59 -0
  4. data/.release-please-manifest.json +3 -0
  5. data/.rubocop.yml +10 -0
  6. data/.rubocop_todo.yml +10 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +90 -0
  9. data/Gemfile +22 -0
  10. data/Gemfile.lock +204 -0
  11. data/LICENSE +21 -0
  12. data/README.md +1171 -0
  13. data/Rakefile +31 -0
  14. data/descope.gemspec +34 -0
  15. data/examples/ruby/Gemfile +4 -0
  16. data/examples/ruby/Gemfile.lock +41 -0
  17. data/examples/ruby/access_key_app.rb +45 -0
  18. data/examples/ruby/enchantedlink_app.rb +65 -0
  19. data/examples/ruby/magiclink_app.rb +81 -0
  20. data/examples/ruby/management/Gemfile +5 -0
  21. data/examples/ruby/management/Gemfile.lock +38 -0
  22. data/examples/ruby/management/access_key_app.rb +71 -0
  23. data/examples/ruby/management/audit_app.rb +25 -0
  24. data/examples/ruby/management/authz_app.rb +135 -0
  25. data/examples/ruby/management/authz_files.json +229 -0
  26. data/examples/ruby/management/flow_app.rb +57 -0
  27. data/examples/ruby/management/permission_app.rb +56 -0
  28. data/examples/ruby/management/role_app.rb +58 -0
  29. data/examples/ruby/management/tenant_app.rb +60 -0
  30. data/examples/ruby/management/user_app.rb +60 -0
  31. data/examples/ruby/oauth_app.rb +39 -0
  32. data/examples/ruby/otp_app.rb +50 -0
  33. data/examples/ruby/password_app.rb +76 -0
  34. data/examples/ruby/saml_app.rb +38 -0
  35. data/examples/ruby-on-rails-api/descope/.dockerignore +37 -0
  36. data/examples/ruby-on-rails-api/descope/.gitattributes +9 -0
  37. data/examples/ruby-on-rails-api/descope/.gitignore +40 -0
  38. data/examples/ruby-on-rails-api/descope/.node-version +1 -0
  39. data/examples/ruby-on-rails-api/descope/.ruby-version +1 -0
  40. data/examples/ruby-on-rails-api/descope/Dockerfile +75 -0
  41. data/examples/ruby-on-rails-api/descope/Gemfile +67 -0
  42. data/examples/ruby-on-rails-api/descope/Gemfile.lock +284 -0
  43. data/examples/ruby-on-rails-api/descope/Procfile.dev +3 -0
  44. data/examples/ruby-on-rails-api/descope/README.md +54 -0
  45. data/examples/ruby-on-rails-api/descope/Rakefile +6 -0
  46. data/examples/ruby-on-rails-api/descope/app/assets/builds/.keep +0 -0
  47. data/examples/ruby-on-rails-api/descope/app/assets/config/manifest.js +3 -0
  48. data/examples/ruby-on-rails-api/descope/app/assets/images/.keep +0 -0
  49. data/examples/ruby-on-rails-api/descope/app/assets/images/descope.jpeg +0 -0
  50. data/examples/ruby-on-rails-api/descope/app/assets/images/favicon.ico +0 -0
  51. data/examples/ruby-on-rails-api/descope/app/assets/images/logo192.png +0 -0
  52. data/examples/ruby-on-rails-api/descope/app/assets/images/logo512.png +0 -0
  53. data/examples/ruby-on-rails-api/descope/app/assets/stylesheets/application.bootstrap.scss +67 -0
  54. data/examples/ruby-on-rails-api/descope/app/channels/application_cable/channel.rb +4 -0
  55. data/examples/ruby-on-rails-api/descope/app/channels/application_cable/connection.rb +4 -0
  56. data/examples/ruby-on-rails-api/descope/app/controllers/application_controller.rb +2 -0
  57. data/examples/ruby-on-rails-api/descope/app/controllers/concerns/.keep +0 -0
  58. data/examples/ruby-on-rails-api/descope/app/controllers/homepage_controller.rb +4 -0
  59. data/examples/ruby-on-rails-api/descope/app/controllers/session_controller.rb +66 -0
  60. data/examples/ruby-on-rails-api/descope/app/helpers/application_helper.rb +2 -0
  61. data/examples/ruby-on-rails-api/descope/app/helpers/homepage_helper.rb +2 -0
  62. data/examples/ruby-on-rails-api/descope/app/helpers/session_helper.rb +2 -0
  63. data/examples/ruby-on-rails-api/descope/app/javascript/App.css +53 -0
  64. data/examples/ruby-on-rails-api/descope/app/javascript/application.js +5 -0
  65. data/examples/ruby-on-rails-api/descope/app/javascript/components/App.jsx +4 -0
  66. data/examples/ruby-on-rails-api/descope/app/javascript/components/Dashboard.jsx +60 -0
  67. data/examples/ruby-on-rails-api/descope/app/javascript/components/Home.jsx +27 -0
  68. data/examples/ruby-on-rails-api/descope/app/javascript/components/Login.jsx +45 -0
  69. data/examples/ruby-on-rails-api/descope/app/javascript/components/Profile.jsx +81 -0
  70. data/examples/ruby-on-rails-api/descope/app/javascript/components/index.html +11 -0
  71. data/examples/ruby-on-rails-api/descope/app/javascript/components/index.jsx +24 -0
  72. data/examples/ruby-on-rails-api/descope/app/javascript/controllers/application.js +9 -0
  73. data/examples/ruby-on-rails-api/descope/app/javascript/controllers/index.js +5 -0
  74. data/examples/ruby-on-rails-api/descope/app/javascript/reportWebVitals.js +13 -0
  75. data/examples/ruby-on-rails-api/descope/app/javascript/routes/index.jsx +17 -0
  76. data/examples/ruby-on-rails-api/descope/app/jobs/application_job.rb +7 -0
  77. data/examples/ruby-on-rails-api/descope/app/mailers/application_mailer.rb +4 -0
  78. data/examples/ruby-on-rails-api/descope/app/models/application_record.rb +3 -0
  79. data/examples/ruby-on-rails-api/descope/app/models/concerns/.keep +0 -0
  80. data/examples/ruby-on-rails-api/descope/app/views/homepage/index.html.erb +2 -0
  81. data/examples/ruby-on-rails-api/descope/app/views/layouts/application.html.erb +16 -0
  82. data/examples/ruby-on-rails-api/descope/app/views/layouts/mailer.html.erb +13 -0
  83. data/examples/ruby-on-rails-api/descope/app/views/layouts/mailer.text.erb +1 -0
  84. data/examples/ruby-on-rails-api/descope/app/views/session/index.html.erb +2 -0
  85. data/examples/ruby-on-rails-api/descope/bin/bundle +109 -0
  86. data/examples/ruby-on-rails-api/descope/bin/dev +11 -0
  87. data/examples/ruby-on-rails-api/descope/bin/docker-entrypoint +8 -0
  88. data/examples/ruby-on-rails-api/descope/bin/rails +4 -0
  89. data/examples/ruby-on-rails-api/descope/bin/rake +4 -0
  90. data/examples/ruby-on-rails-api/descope/bin/setup +36 -0
  91. data/examples/ruby-on-rails-api/descope/build.js +30 -0
  92. data/examples/ruby-on-rails-api/descope/config/application.rb +42 -0
  93. data/examples/ruby-on-rails-api/descope/config/boot.rb +4 -0
  94. data/examples/ruby-on-rails-api/descope/config/cable.yml +10 -0
  95. data/examples/ruby-on-rails-api/descope/config/config.yml +9 -0
  96. data/examples/ruby-on-rails-api/descope/config/credentials.yml.enc +1 -0
  97. data/examples/ruby-on-rails-api/descope/config/database.yml +25 -0
  98. data/examples/ruby-on-rails-api/descope/config/environment.rb +5 -0
  99. data/examples/ruby-on-rails-api/descope/config/environments/development.rb +76 -0
  100. data/examples/ruby-on-rails-api/descope/config/environments/production.rb +97 -0
  101. data/examples/ruby-on-rails-api/descope/config/environments/test.rb +64 -0
  102. data/examples/ruby-on-rails-api/descope/config/initializers/assets.rb +13 -0
  103. data/examples/ruby-on-rails-api/descope/config/initializers/content_security_policy.rb +25 -0
  104. data/examples/ruby-on-rails-api/descope/config/initializers/filter_parameter_logging.rb +8 -0
  105. data/examples/ruby-on-rails-api/descope/config/initializers/inflections.rb +16 -0
  106. data/examples/ruby-on-rails-api/descope/config/initializers/load_config.rb +12 -0
  107. data/examples/ruby-on-rails-api/descope/config/initializers/permissions_policy.rb +13 -0
  108. data/examples/ruby-on-rails-api/descope/config/locales/en.yml +31 -0
  109. data/examples/ruby-on-rails-api/descope/config/puma.rb +35 -0
  110. data/examples/ruby-on-rails-api/descope/config/routes.rb +18 -0
  111. data/examples/ruby-on-rails-api/descope/config/storage.yml +34 -0
  112. data/examples/ruby-on-rails-api/descope/config.ru +6 -0
  113. data/examples/ruby-on-rails-api/descope/db/seeds.rb +9 -0
  114. data/examples/ruby-on-rails-api/descope/lib/assets/.keep +0 -0
  115. data/examples/ruby-on-rails-api/descope/lib/tasks/.keep +0 -0
  116. data/examples/ruby-on-rails-api/descope/log/.keep +0 -0
  117. data/examples/ruby-on-rails-api/descope/package-lock.json +19680 -0
  118. data/examples/ruby-on-rails-api/descope/package.json +51 -0
  119. data/examples/ruby-on-rails-api/descope/public/404.html +67 -0
  120. data/examples/ruby-on-rails-api/descope/public/422.html +67 -0
  121. data/examples/ruby-on-rails-api/descope/public/500.html +66 -0
  122. data/examples/ruby-on-rails-api/descope/public/apple-touch-icon-precomposed.png +0 -0
  123. data/examples/ruby-on-rails-api/descope/public/apple-touch-icon.png +0 -0
  124. data/examples/ruby-on-rails-api/descope/public/favicon.ico +0 -0
  125. data/examples/ruby-on-rails-api/descope/public/robots.txt +1 -0
  126. data/examples/ruby-on-rails-api/descope/storage/.keep +0 -0
  127. data/examples/ruby-on-rails-api/descope/tmp/.keep +0 -0
  128. data/examples/ruby-on-rails-api/descope/tmp/pids/.keep +0 -0
  129. data/examples/ruby-on-rails-api/descope/tmp/storage/.keep +0 -0
  130. data/examples/ruby-on-rails-api/descope/vendor/.keep +0 -0
  131. data/examples/ruby-on-rails-api/descope/yarn.lock +10780 -0
  132. data/lib/descope/api/v1/auth/enchantedlink.rb +156 -0
  133. data/lib/descope/api/v1/auth/magiclink.rb +170 -0
  134. data/lib/descope/api/v1/auth/oauth.rb +72 -0
  135. data/lib/descope/api/v1/auth/otp.rb +186 -0
  136. data/lib/descope/api/v1/auth/password.rb +100 -0
  137. data/lib/descope/api/v1/auth/saml.rb +48 -0
  138. data/lib/descope/api/v1/auth/totp.rb +72 -0
  139. data/lib/descope/api/v1/auth.rb +452 -0
  140. data/lib/descope/api/v1/management/access_key.rb +81 -0
  141. data/lib/descope/api/v1/management/audit.rb +82 -0
  142. data/lib/descope/api/v1/management/authz.rb +165 -0
  143. data/lib/descope/api/v1/management/common.rb +147 -0
  144. data/lib/descope/api/v1/management/flow.rb +55 -0
  145. data/lib/descope/api/v1/management/password.rb +58 -0
  146. data/lib/descope/api/v1/management/permission.rb +48 -0
  147. data/lib/descope/api/v1/management/project.rb +53 -0
  148. data/lib/descope/api/v1/management/role.rb +48 -0
  149. data/lib/descope/api/v1/management/scim.rb +206 -0
  150. data/lib/descope/api/v1/management/sso_settings.rb +153 -0
  151. data/lib/descope/api/v1/management/tenant.rb +71 -0
  152. data/lib/descope/api/v1/management/user.rb +619 -0
  153. data/lib/descope/api/v1/management.rb +38 -0
  154. data/lib/descope/api/v1/session.rb +84 -0
  155. data/lib/descope/api/v1.rb +13 -0
  156. data/lib/descope/client.rb +6 -0
  157. data/lib/descope/exception.rb +50 -0
  158. data/lib/descope/mixins/common.rb +129 -0
  159. data/lib/descope/mixins/headers.rb +15 -0
  160. data/lib/descope/mixins/http.rb +133 -0
  161. data/lib/descope/mixins/initializer.rb +80 -0
  162. data/lib/descope/mixins/logging.rb +30 -0
  163. data/lib/descope/mixins/validation.rb +79 -0
  164. data/lib/descope/mixins.rb +22 -0
  165. data/lib/descope/version.rb +7 -0
  166. data/lib/descope.rb +9 -0
  167. data/lib/descope_client.rb +5 -0
  168. data/release-please-config.json +18 -0
  169. data/renovate.json +6 -0
  170. data/spec/factories/user.rb +16 -0
  171. data/spec/lib.descope/api/v1/auth/enchantedlink_spec.rb +159 -0
  172. data/spec/lib.descope/api/v1/auth/magiclink_spec.rb +282 -0
  173. data/spec/lib.descope/api/v1/auth/oauth_spec.rb +117 -0
  174. data/spec/lib.descope/api/v1/auth/otp_spec.rb +285 -0
  175. data/spec/lib.descope/api/v1/auth/password_spec.rb +124 -0
  176. data/spec/lib.descope/api/v1/auth/saml_spec.rb +55 -0
  177. data/spec/lib.descope/api/v1/auth/totp_spec.rb +70 -0
  178. data/spec/lib.descope/api/v1/auth_spec.rb +372 -0
  179. data/spec/lib.descope/api/v1/management/access_key_spec.rb +118 -0
  180. data/spec/lib.descope/api/v1/management/audit_spec.rb +78 -0
  181. data/spec/lib.descope/api/v1/management/authz_spec.rb +336 -0
  182. data/spec/lib.descope/api/v1/management/flow_spec.rb +78 -0
  183. data/spec/lib.descope/api/v1/management/password_spec.rb +25 -0
  184. data/spec/lib.descope/api/v1/management/permission_spec.rb +81 -0
  185. data/spec/lib.descope/api/v1/management/project_spec.rb +63 -0
  186. data/spec/lib.descope/api/v1/management/role_spec.rb +85 -0
  187. data/spec/lib.descope/api/v1/management/scim_spec.rb +312 -0
  188. data/spec/lib.descope/api/v1/management/sso_settings_spec.rb +172 -0
  189. data/spec/lib.descope/api/v1/management/tenant_spec.rb +141 -0
  190. data/spec/lib.descope/api/v1/management/user_spec.rb +667 -0
  191. data/spec/lib.descope/api/v1/session_spec.rb +117 -0
  192. data/spec/lib.descope/client_spec.rb +40 -0
  193. data/spec/spec_helper.rb +72 -0
  194. data/spec/support/client_config.rb +14 -0
  195. data/spec/support/dummy_class.rb +36 -0
  196. data/spec/support/utils.rb +32 -0
  197. metadata +420 -0
@@ -0,0 +1,67 @@
1
+ @import 'bootstrap/scss/bootstrap';
2
+ @import 'bootstrap-icons/font/bootstrap-icons';
3
+
4
+ @import url('https://fonts.googleapis.com/css2?family=Golos+Text:wght@500&display=swap');
5
+
6
+ .page {
7
+ display: flex;
8
+ flex-direction: column;
9
+ align-items: center;
10
+ justify-content: center;
11
+ margin-bottom: 5vh;
12
+ }
13
+
14
+ .title {
15
+ margin-top: 10vh;
16
+ margin-bottom: 5vh;
17
+ font-size: 2em;
18
+ }
19
+
20
+ .link {
21
+ text-decoration: none;
22
+ margin-bottom: 5vh;
23
+ }
24
+
25
+ .btn {
26
+ border: None;
27
+ background-color: #00BD67;
28
+ padding: 15px 25px;
29
+ color: #fff;
30
+ font-size: 1.1em;
31
+ border-radius: 9px;
32
+ margin-top: 12px;
33
+ margin-right: 1vh;
34
+ }
35
+
36
+ .btn:hover, .btn:focus, .btn:active, .btn.active, .open>.dropdown-toggle.btn {
37
+ color: #fff;
38
+ background-color: #00b3db;
39
+ border-color: #285e8e; /*set the color you want here*/
40
+ }
41
+
42
+ .student {
43
+ margin-bottom: 5vh;
44
+ }
45
+
46
+ .students {
47
+ font-size: 1.5em;
48
+ }
49
+
50
+ body {
51
+ margin: 0;
52
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
53
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
54
+ sans-serif;
55
+ -webkit-font-smoothing: antialiased;
56
+ -moz-osx-font-smoothing: grayscale;
57
+ }
58
+
59
+ code {
60
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
61
+ monospace;
62
+ }
63
+
64
+ .logout {
65
+ position: relative;
66
+ top: -22px;
67
+ }
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,4 @@
1
+ class HomepageController < ApplicationController
2
+ def index
3
+ end
4
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'descope'
4
+
5
+ class SessionController < ApplicationController
6
+ attr_reader :jwt_response
7
+
8
+ before_action :authenticate_request
9
+
10
+
11
+ def get_roles
12
+ puts '🔐 Getting roles...'
13
+ if @jwt_response['roles'].nil? || @jwt_response['roles'].empty?
14
+ puts '🔐 Empty roles! You are not a trained Descope user!'
15
+ return render json: { secretMessage: 'Empty roles! You are now a trained Descope user!', roles: [] }
16
+ end
17
+
18
+ roles = @jwt_response['roles']
19
+ puts "🔐 Got Roles: #{roles}"
20
+ render json: { secretMessage: 'You are now a trained Descope user!', roles: }
21
+ end
22
+
23
+ def get_role_data
24
+ valid_student_role = descope_client.validate_roles(
25
+ jwt_response: @jwt_response, roles: ['student']
26
+ )
27
+ valid_teacher_role = descope_client.validate_roles(
28
+ jwt_response: @jwt_response, roles: ['teacher']
29
+ )
30
+ if valid_student_role && valid_teacher_role
31
+ render json: { valid_teacher: valid_teacher_role, valid_student: valid_student_role }
32
+ else
33
+ render json: { valid_teacher: 'no valid teacher role found', valid_student: 'no valid student role found' }
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def authenticate_request
40
+ puts '🔐 Authenticating request...'
41
+ unless request.headers['Authorization'].nil? # check if token is present in the request header
42
+ auth_request = request.headers['Authorization']
43
+ session_token = auth_request&.remove('Bearer ')
44
+ end
45
+
46
+ return render json: { error: '❌ Invalid session token!' }, status: :unauthorized unless session_token
47
+
48
+
49
+ begin
50
+ @jwt_response = descope_client.validate_session(session_token:)
51
+ rescue Descope::AuthException
52
+ return render json: { error: '❌ Invalid session token!' }, status: :unauthorized
53
+ end
54
+
55
+ logger.info "🔐 Authenticated successfully! token validated: #{@jwt_response}"
56
+ @jwt_response
57
+ end
58
+
59
+ def descope_client
60
+ @descope_client ||= Descope::Client.new({ project_id: APP_CONFIG['react_app_project_id'], log_level: APP_CONFIG['ruby_sdk_log_level'] })
61
+ rescue Descope::AuthException => e
62
+ logger.error "Failed to initialize descope sdk: #{e.message}"
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module HomepageHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module SessionHelper
2
+ end
@@ -0,0 +1,53 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Golos+Text:wght@500&display=swap');
2
+
3
+ .page {
4
+ display: flex;
5
+ flex-direction: column;
6
+ align-items: center;
7
+ justify-content: center;
8
+ margin-bottom: 5vh;
9
+ }
10
+
11
+ .title {
12
+ margin-top: 10vh;
13
+ margin-bottom: 5vh;
14
+ font-size: 2em;
15
+ }
16
+
17
+ .link {
18
+ text-decoration: none;
19
+ margin-bottom: 5vh;
20
+ }
21
+
22
+ .btn {
23
+ border: None;
24
+ background-color: #00BD67;
25
+ padding: 15px 25px;
26
+ color: #fff;
27
+ font-size: 1.1em;
28
+ border-radius: 9px;
29
+ margin-top: 12px;
30
+ margin-right: 1vh;
31
+ }
32
+
33
+ .student {
34
+ margin-bottom: 5vh;
35
+ }
36
+
37
+ .students {
38
+ font-size: 1.5em;
39
+ }
40
+
41
+ body {
42
+ margin: 0;
43
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
44
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
45
+ sans-serif;
46
+ -webkit-font-smoothing: antialiased;
47
+ -moz-osx-font-smoothing: grayscale;
48
+ }
49
+
50
+ code {
51
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
52
+ monospace;
53
+ }
@@ -0,0 +1,5 @@
1
+ // Entry point for the build script in your package.json
2
+ import "@hotwired/turbo-rails"
3
+ import "./controllers"
4
+ import * as bootstrap from "bootstrap"
5
+ import "./components"
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import Routes from "../routes";
3
+
4
+ export default props => <>{Routes}</>;
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+ import { useEffect, useState } from "react";
3
+ import { Link } from "react-router-dom";
4
+ import { useNavigate } from "react-router-dom";
5
+ import { getSessionToken } from '@descope/react-sdk';
6
+ import '../App.css';
7
+
8
+ function Dashboard() {
9
+ const sessionToken = getSessionToken(); // get the session token
10
+ const navigate = useNavigate()
11
+ const [roles, setRoles] = useState({
12
+ teacherRole: false,
13
+ studentRole: false
14
+ })
15
+
16
+ useEffect(() => {
17
+ fetch('/get_role_data', { // call the api endpoint from the flask server
18
+ headers: {
19
+ Accept: 'application/json',
20
+ Authorization: 'Bearer ' + sessionToken,
21
+ }
22
+ }).then(data => {
23
+ if (data.status === 401) {
24
+ navigate('/login')
25
+ }
26
+ return data.json()
27
+ }).then(jsonData => {
28
+ setRoles({
29
+ teacherRole: jsonData.valid_teacher,
30
+ studentRole: jsonData.valid_student
31
+ })
32
+ }).catch((err) => {
33
+ console.log(err)
34
+ navigate('/login')
35
+ })
36
+ }, [])
37
+
38
+ return (
39
+ <div className='page'>
40
+ <h1 className='title'>Dashboard</h1>
41
+ <Link className='link btn' to="/profile">Profile</Link>
42
+ {roles.teacherRole && (
43
+ <div className='page'>
44
+ <h1>Welcome back Teacher!</h1>
45
+ <p className='students'>You have 50+ students currently 🧑‍🎓</p>
46
+ </div>
47
+ )}
48
+ {roles.studentRole && (
49
+ <div className='page'>
50
+ <h1>Welcome back Student!</h1>
51
+ <p className='student'>Unlucky! You have homework!</p>
52
+ <iframe src="https://giphy.com/embed/H9UeFGxZz4cBG" width="469" height="480" allowFullScreen></iframe>
53
+ </div>
54
+ )}
55
+ </div>
56
+ )
57
+ }
58
+
59
+
60
+ export default Dashboard;
@@ -0,0 +1,27 @@
1
+ import '../App.css';
2
+ import { useEffect } from "react";
3
+ import { Link } from "react-router-dom";
4
+ import { useSession } from '@descope/react-sdk'
5
+ import { useNavigate } from "react-router-dom";
6
+ import React from "react";
7
+
8
+ function Home() {
9
+ const { isAuthenticated } = useSession()
10
+ const navigate = useNavigate()
11
+
12
+ useEffect(() => {
13
+ if (isAuthenticated) {
14
+ return navigate("/profile");
15
+ }
16
+ }, [isAuthenticated]) // listen for when isAuthenticated has changed
17
+
18
+ return (
19
+ <div className='page'>
20
+ <h1 className='title'>Descope - Ruby On Rails Example App</h1>
21
+ <Link className='link btn' to="/login">Login</Link>
22
+ <iframe src="https://giphy.com/embed/bKj0qEKTVBdF2o5Dgn" width="480" height="352" allowFullScreen></iframe>
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export default Home;
@@ -0,0 +1,45 @@
1
+ import '../App.css';
2
+ import React, { useEffect } from "react";
3
+ import { Descope, useSession, useUser } from '@descope/react-sdk'
4
+ import { useNavigate } from "react-router-dom";
5
+
6
+
7
+ function Login() {
8
+ // isAuthenticated: boolean - is the user authenticated?
9
+ // isSessionLoading: boolean - Use this for showing loading screens while objects are being loaded
10
+ const { isAuthenticated, isSessionLoading } = useSession()
11
+ // isUserLoading: boolean - Use this for showing loading screens while objects are being loaded
12
+ const { isUserLoading } = useUser()
13
+ const navigate = useNavigate()
14
+
15
+ useEffect(() => {
16
+ if (isAuthenticated) {
17
+ return navigate("/profile");
18
+ }
19
+ }, [isAuthenticated]) // listen for when isAuthenticated has changed
20
+
21
+ return (
22
+ <div className='page'>
23
+ {
24
+ (isSessionLoading || isUserLoading) && <p>Loading...</p>
25
+ }
26
+
27
+ {!isAuthenticated &&
28
+ (
29
+ <>
30
+ <h1 className='title'>Login/SignUp to see the Secret Message!</h1>
31
+ <Descope
32
+ flowId="sign-up-or-in"
33
+ onSuccess = {(e) => console.log(e.detail.user)}
34
+ onError={(e) => console.log('Could not log in! ' + e.detail.error)}
35
+ theme="light"
36
+ />
37
+ </>
38
+ )
39
+ }
40
+ </div>
41
+ )
42
+ }
43
+
44
+
45
+ export default Login;
@@ -0,0 +1,81 @@
1
+ import React from "react";
2
+ import { useState, useEffect, useCallback } from "react";
3
+ import { useDescope, useUser, getSessionToken, useSession } from '@descope/react-sdk'
4
+ import { useNavigate } from "react-router-dom";
5
+ import { Link } from "react-router-dom";
6
+ import '../App.css';
7
+
8
+
9
+ function Profile() {
10
+ const { isSessionLoading } = useSession()
11
+
12
+ const { user } = useUser()
13
+ const { logout } = useDescope()
14
+ const navigate = useNavigate()
15
+
16
+ const [secret, setSecret] = useState({
17
+ secret: "",
18
+ roles: []
19
+ })
20
+
21
+ const sessionToken = getSessionToken(); // get the session token
22
+
23
+ const logoutUser = useCallback(async () => {
24
+ await logout()
25
+ return navigate('/login')
26
+ }, [logout, navigate]);
27
+
28
+ useEffect(() => {
29
+ fetch('/get_roles', { // call the api endpoint from the flask server
30
+ headers: {
31
+ Accept: 'application/json',
32
+ Authorization: 'Bearer ' + sessionToken,
33
+ }
34
+ }).then(res => {
35
+ if (!res.ok) {
36
+ throw Error(res.statusText);
37
+ }
38
+
39
+ if (res.status === 401) {
40
+ navigate('/login')
41
+ }
42
+ return res.json()
43
+ }).then(jsonData => {
44
+ setSecret({
45
+ secret: jsonData.secretMessage,
46
+ roles: jsonData.roles
47
+ })
48
+ }).catch((err) => {
49
+ console.log(err)
50
+ navigate('/login')
51
+ })
52
+ }, [])
53
+
54
+ return (
55
+ <>
56
+ {user && (
57
+ <div className='page profile'>
58
+ <div>
59
+ <h1 className='title'>Hello {user.name} 👋</h1>
60
+ <div>My Private Component</div>
61
+ <p>Secret Message: <span style={{ padding: "5px 10px", color: "white", backgroundColor: "black" }}>{secret.secret}</span></p>
62
+ <p>Your Role(s): </p>
63
+ {!secret.roles || secret.roles.length === 0 ?
64
+ <p><span style={{ color: "green", fontWeight: "bold"}}>No role found!</span></p>
65
+ :
66
+ secret.roles.map((role, i) => (
67
+ <p key={i}><span style={{ color: "green", fontWeight: "bold" }}>{role}</span></p>
68
+ ))
69
+ }
70
+ <Link className='link btn' to="/">Home</Link>
71
+ <Link className='link btn' to="/dashboard">Dashboard</Link>
72
+ <button className='btn logout' onClick={logoutUser}>Logout</button>
73
+ </div>
74
+ </div>
75
+ )}
76
+ </>
77
+ )
78
+ }
79
+
80
+
81
+ export default Profile;
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Descope React demo app</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ </head>
7
+ <body>
8
+ <div id="root"></div>
9
+ <script type="module" src="./index.jsx"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from "./App";
4
+ import reportWebVitals from '../reportWebVitals';
5
+ import { AuthProvider } from '@descope/react-sdk'
6
+ import '../App.css';
7
+
8
+ document.addEventListener("turbo:load", () => {
9
+ document.body.innerHTML = '<div id="root"></div>';
10
+ const root = ReactDOM.createRoot(document.getElementById("root"));
11
+
12
+ root.render(
13
+ <React.StrictMode>
14
+ <AuthProvider projectId={process.env.REACT_APP_PROJECT_ID}>
15
+ <App />
16
+ </AuthProvider>
17
+ </React.StrictMode>
18
+ );
19
+ });
20
+
21
+ // If you want to start measuring performance in your app, pass a function
22
+ // to log results (for example: reportWebVitals(console.log))
23
+ // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
24
+ reportWebVitals();
@@ -0,0 +1,9 @@
1
+ import { Application } from "@hotwired/stimulus"
2
+
3
+ const application = Application.start()
4
+
5
+ // Configure Stimulus development experience
6
+ application.debug = false
7
+ window.Stimulus = application
8
+
9
+ export { application }
@@ -0,0 +1,5 @@
1
+ // This file is auto-generated by ./bin/rails stimulus:manifest:update
2
+ // Run that command whenever you add a new controller or create them with
3
+ // ./bin/rails generate stimulus controllerName
4
+
5
+ import { application } from "./application"
@@ -0,0 +1,13 @@
1
+ const reportWebVitals = onPerfEntry => {
2
+ if (onPerfEntry && onPerfEntry instanceof Function) {
3
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4
+ getCLS(onPerfEntry);
5
+ getFID(onPerfEntry);
6
+ getFCP(onPerfEntry);
7
+ getLCP(onPerfEntry);
8
+ getTTFB(onPerfEntry);
9
+ });
10
+ }
11
+ };
12
+
13
+ export default reportWebVitals;
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
3
+ import Home from "../components/Home";
4
+ import Login from "../components/Login";
5
+ import Profile from "../components/Profile";
6
+ import Dashboard from "../components/Dashboard";
7
+
8
+ export default (
9
+ <Router>
10
+ <Routes>
11
+ <Route path="/" element={<Home />} />
12
+ <Route path='/login' element={<Login />} />
13
+ <Route path='/profile' element={<Profile />} />
14
+ <Route path='/dashboard' element={<Dashboard />} />
15
+ </Routes>
16
+ </Router>
17
+ );
@@ -0,0 +1,7 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ # Automatically retry jobs that encountered a deadlock
3
+ # retry_on ActiveRecord::Deadlocked
4
+
5
+ # Most jobs are safe to ignore if the underlying records are no longer available
6
+ # discard_on ActiveJob::DeserializationError
7
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: "from@example.com"
3
+ layout "mailer"
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ primary_abstract_class
3
+ end
@@ -0,0 +1,2 @@
1
+ <h1>Homepage#index</h1>
2
+ <p>Find me in app/views/homepage/index.html.erb</p>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>RailsDescope</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
10
+ <%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
11
+ </head>
12
+
13
+ <body>
14
+ <%= yield %>
15
+ </body>
16
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1,2 @@
1
+ <h1>Session#index</h1>
2
+ <p>Find me in app/views/session/index.html.erb</p>