Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: JavaScript Integration Tests
name: Integration Tests

on:
workflow_dispatch:
Expand Down Expand Up @@ -31,3 +31,40 @@ jobs:
ORY_SDK_URL: ${{ secrets.ORY_SDK_URL }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}

test-java-integration:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
cache: "maven"
- name: Install test app dependencies
run: |
cd tests/jest/apps/identity-get-started-java
mvn dependency:resolve
- name: Start test server
run: |
cd tests/jest/apps/identity-get-started-java
mvn spring-boot:run &
env:
ORY_SDK_URL: ${{ secrets.ORY_SDK_URL }}
EXAMPLES_TEST_APP_PORT: "3000"
- name: Wait for server to be ready
run: |
timeout 30 bash -c 'until curl -f http://127.0.0.1:3000/configure; do sleep 1; done'
- name: Run Java integration tests
run: |
cd tests/jest/apps/identity-get-started-java
mvn test
env:
ORY_SDK_URL: ${{ secrets.ORY_SDK_URL }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
- name: Stop test server
if: always()
run: |
pkill -f "spring-boot:run" || true
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import sh.ory.ApiException;
import sh.ory.api.FrontendApi;
import sh.ory.model.Session;

import java.io.IOException;

@RestController
public class LoginHandler {
private final FrontendApi ory;
private final String baseUrl;

public LoginHandler(FrontendApi ory, String baseUrl) {
this.ory = ory;
this.baseUrl = baseUrl;
}

@GetMapping("/login")
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
String cookieHeader = request.getHeader("Cookie");

try {
Session session = ory.toSession(null, cookieHeader, null);
if (session != null && session.getActive() != null && session.getActive()) {
// Session is valid, return session data as JSON
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write(session.toString());
return;
}
} catch (ApiException e) {
// Session is invalid or doesn't exist
}

// Redirect to login page
response.sendRedirect(baseUrl + "/self-service/login/browser");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import sh.ory.ApiException;
import sh.ory.api.FrontendApi;
import sh.ory.model.LogoutFlow;

import java.io.IOException;

@RestController
public class LogoutHandler {
private final FrontendApi ory;

public LogoutHandler(FrontendApi ory) {
this.ory = ory;
}

@GetMapping("/logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
String cookieHeader = request.getHeader("Cookie");

try {
LogoutFlow logoutFlow = ory.createBrowserLogoutFlow(cookieHeader);
String logoutUrl = logoutFlow.getLogoutUrl();
if (logoutUrl != null) {
response.sendRedirect(logoutUrl);
return;
}
} catch (ApiException e) {
// Error creating logout flow
}

// Redirect to home page if there's an error
response.sendRedirect("/");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import sh.ory.ApiClient;
import sh.ory.Configuration;
import sh.ory.api.FrontendApi;

public class SetupDev {
public static final String baseUrl = System.getenv("ORY_SDK_URL") != null
? System.getenv("ORY_SDK_URL")
: "http://localhost:4000";

public static FrontendApi createOryClient() {
ApiClient apiClient = Configuration.getDefaultApiClient();
apiClient.setBasePath(baseUrl);
return new FrontendApi(apiClient);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import sh.ory.ApiException;
import sh.ory.api.FrontendApi;
import sh.ory.model.Session;

import java.io.IOException;

@RestController
public class SignUpHandler {
private final FrontendApi ory;
private final String baseUrl;

public SignUpHandler(FrontendApi ory, String baseUrl) {
this.ory = ory;
this.baseUrl = baseUrl;
}

@GetMapping("/signup")
public void signUp(HttpServletRequest request, HttpServletResponse response) throws IOException {
String cookieHeader = request.getHeader("Cookie");

try {
Session session = ory.toSession(null, cookieHeader, null);
if (session != null && session.getActive() != null && session.getActive()) {
// Session is valid, return session data as JSON
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write(session.toString());
return;
}
} catch (ApiException e) {
// Session is invalid or doesn't exist
}

// Redirect to registration page
response.sendRedirect(baseUrl + "/self-service/registration/browser");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package session;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
public class RefreshSessionHandler {
private final String baseUrl;

public RefreshSessionHandler(String baseUrl) {
this.baseUrl = baseUrl;
}

@GetMapping("/refresh-session")
public void refreshSession(HttpServletResponse response) throws IOException {
// Redirect to login with refresh=true parameter
response.sendRedirect(baseUrl + "/ui/login?refresh=true");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package session;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import sh.ory.ApiException;
import sh.ory.api.FrontendApi;
import sh.ory.model.Session;

import java.io.IOException;

public class RequireAuth implements HandlerInterceptor {
private final FrontendApi ory;
private final String baseUrl;

public RequireAuth(FrontendApi ory, String baseUrl) {
this.ory = ory;
this.baseUrl = baseUrl;
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
String cookieHeader = request.getHeader("Cookie");

try {
Session session = ory.toSession(null, cookieHeader, null);
if (session != null && session.getActive() != null && session.getActive()) {
// Store session in request attribute
request.setAttribute("session", session);
return true;
}
} catch (ApiException e) {
// Session is invalid or doesn't exist
}

// Redirect to login page
response.sendRedirect(baseUrl + "/self-service/login/browser");
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package session;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import sh.ory.model.Session;

@RestController
public class SessionHandler {
@GetMapping("/session")
public ResponseEntity<Object> getSession(HttpServletRequest request) {
Session session = (Session) request.getAttribute("session");
if (session != null && session.getIdentity() != null && session.getIdentity().getTraits() != null) {
return ResponseEntity.ok(session.getIdentity().getTraits());
}
return ResponseEntity.notFound().build();
}
}
25 changes: 25 additions & 0 deletions docs/identities/get-started/session-management.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import nextRefreshSession from '!!raw-loader!./_common/code-examples/nextjs/sess
import nextCheckSession from '!!raw-loader!./_common/code-examples/nextjs/session/middleware.ts'
import goCheckSession from '!!raw-loader!./_common/code-examples/go/middleware.go'
import goRefreshHandler from '!!raw-loader!./_common/code-examples/go/refresh_handler.go'
import javaRequireAuth from '!!raw-loader!./_common/code-examples/java/session/RequireAuth.java'
import javaSessionHandler from '!!raw-loader!./_common/code-examples/java/session/SessionHandler.java'
import javaRefreshSession from '!!raw-loader!./_common/code-examples/java/session/RefreshSessionHandler.java'
```

After a user has logged in, Ory creates a session cookie that your application can use to verify the user's authentication status.
Expand Down Expand Up @@ -51,6 +54,19 @@ You can protect routes by checking for a session cookie.
<CodeBlock language="go" title="middleware.go">{goCheckSession}</CodeBlock>
```

```mdx-code-block
</TabItem>
<TabItem value="java">
```

```mdx-code-block
<CodeBlock language="java" title="RequireAuth.java">{javaRequireAuth}</CodeBlock>
```

```mdx-code-block
<CodeBlock language="java" title="SessionHandler.java">{javaSessionHandler}</CodeBlock>
```

```mdx-code-block
</TabItem>
</FrameworkCodeTabs>
Expand Down Expand Up @@ -87,6 +103,15 @@ You can refresh user sessions to extend their expiration time:
<CodeBlock className="language-go" title="refresh_handler.go">{goRefreshHandler}</CodeBlock>
```

```mdx-code-block
</TabItem>
<TabItem value="java">
```

```mdx-code-block
<CodeBlock className="language-java" title="RefreshSessionHandler.java">{javaRefreshSession}</CodeBlock>
```

```mdx-code-block
</TabItem>
</FrameworkCodeTabs>
Expand Down
10 changes: 10 additions & 0 deletions docs/identities/get-started/sign-in.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FrameworkCodeTabs } from '@site/src/components/GuidesComponents'
import jsLogin from '!!raw-loader!./_common/code-examples/js/login.js'
import goLogin from '!!raw-loader!./_common/code-examples/go/login_handler.go'
import nextjsLogin from '!!raw-loader!./_common/code-examples/nextjs/login.tsx'
import javaLogin from '!!raw-loader!./_common/code-examples/java/LoginHandler.java'
```

The sign in flow follows the same pattern as the [sign up flow](/docs/identities/get-started/sign-up) but instead of redirecting
Expand Down Expand Up @@ -48,6 +49,15 @@ to the registration page, it redirects to the login page.

```

```mdx-code-block
</TabItem>
<TabItem value="java">
```

```mdx-code-block
<CodeBlock className="language-java" title={"LoginHandler.java"}>{javaLogin}</CodeBlock>
```

```mdx-code-block
</TabItem>
</FrameworkCodeTabs>
Expand Down
8 changes: 8 additions & 0 deletions docs/identities/get-started/sign-out.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FrameworkCodeTabs, ImplementationSteps } from '@site/src/components/Gui
import jsLogout from '!!raw-loader!./_common/code-examples/js/logout.js'
import nextLogout from '!!raw-loader!./_common/code-examples/nextjs/logout.tsx'
import goLogout from '!!raw-loader!./_common/code-examples/go/logout_handler.go'
import javaLogout from '!!raw-loader!./_common/code-examples/java/LogoutHandler.java'
```

The logout flow allows users to securely terminate their sessions. This guide shows how to implement proper logout functionality
Expand Down Expand Up @@ -43,6 +44,13 @@ in your application.

<CodeBlock className="language-go">{goLogout}</CodeBlock>

```mdx-code-block
</TabItem>
<TabItem value="java">
```

<CodeBlock className="language-java" title={"LogoutHandler.java"}>{javaLogout}</CodeBlock>

```mdx-code-block
</TabItem>
</FrameworkCodeTabs>
Expand Down
10 changes: 10 additions & 0 deletions docs/identities/get-started/sign-up.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FrameworkCodeTabs } from '@site/src/components/GuidesComponents'
import jsSignUp from '!!raw-loader!./_common/code-examples/js/sign-up.js'
import goSignUp from '!!raw-loader!./_common/code-examples/go/signup_handler.go'
import nextSignUp from '!!raw-loader!./_common/code-examples/nextjs/sign-up.tsx'
import javaSignUp from '!!raw-loader!./_common/code-examples/java/SignUpHandler.java'
```

This guide shows how to implement a secure sign up flow that authenticates users and creates sessions.
Expand Down Expand Up @@ -56,6 +57,15 @@ the Ory registration page.

```

```mdx-code-block
</TabItem>
<TabItem value="java">
```

```mdx-code-block
<CodeBlock className="language-java" title={"SignUpHandler.java"}>{javaSignUp}</CodeBlock>
```

```mdx-code-block
</TabItem>
</FrameworkCodeTabs>
Expand Down
1 change: 1 addition & 0 deletions src/components/GuidesComponents/FrameworkCodeTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const DEFAULT_FRAMEWORKS = [
{ value: "javascript", label: "Express (JS)" },
{ value: "nextjs", label: "Next.js" },
{ value: "go", label: "Go" },
{ value: "java", label: "Java" },
]

export const FrameworkCodeTabs = ({ children }) => {
Expand Down
Loading
Loading