Skip to content
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ bin
gradle/wrapper
!gradle/wrapper/gradle-wrapper.jar
!gradle/wrapper/gradle-wrapper.properties

# Eclipse/Buildship
.project
.settings/
130 changes: 130 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Authzed Java Client Examples

This directory contains examples demonstrating how to use the Authzed Java client library from various JVM languages.

## Available Examples

### Java Examples (`v1/`)
- `CallingCheck.java` - Demonstrates basic permission checking with schema writing, relationship creation, and permission checks
- `CallingWatch.java` - Demonstrates watching for changes in SpiceDB with automatic reconnection

### Kotlin Examples (`kotlin/`)
- `CallingCheck.kt` - Same functionality as the Java example, but using idiomatic Kotlin syntax

### Scala Examples (`scala/`)
- `CallingCheck.scala` - Same functionality as the Java example, but using idiomatic Scala syntax

## Installation

The Authzed Java client library works seamlessly with all JVM languages. Choose your build tool and language:

**Note:** You need to include a gRPC transport implementation like `grpc-netty-shaded` to run these examples. The `authzed` library doesn't include a transport by default to give you flexibility in choosing one.

### Maven (Java)

```xml
<dependencies>
<dependency>
<groupId>com.authzed.api</groupId>
<artifactId>authzed</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-api</artifactId>
<version>1.75.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.75.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.75.0</version>
</dependency>
</dependencies>
```

### Gradle (Java/Kotlin)

For `build.gradle`:
```groovy
dependencies {
implementation "com.authzed.api:authzed:1.5.4"
implementation 'io.grpc:grpc-api:1.75.0'
implementation 'io.grpc:grpc-stub:1.75.0'
implementation 'io.grpc:grpc-netty-shaded:1.75.0'
}
```

For `build.gradle.kts` (Kotlin DSL):
```kotlin
dependencies {
implementation("com.authzed.api:authzed:1.5.4")
implementation("io.grpc:grpc-api:1.75.0")
implementation("io.grpc:grpc-stub:1.75.0")
implementation("io.grpc:grpc-netty-shaded:1.75.0")
}
```

### SBT (Scala)

```scala
libraryDependencies ++= Seq(
"com.authzed.api" % "authzed" % "1.5.4",
"io.grpc" % "grpc-api" % "1.75.0",
"io.grpc" % "grpc-stub" % "1.75.0",
"io.grpc" % "grpc-netty-shaded" % "1.75.0"
)
```

## Usage

All examples follow the same pattern:

1. **Create a channel** - Connect to SpiceDB using gRPC
2. **Authenticate** - Use a bearer token for authentication
3. **Create service stubs** - Initialize the schema and permissions services
4. **Write a schema** - Define your permission model
5. **Write relationships** - Create relationships between objects
6. **Check permissions** - Verify if a subject has permission on a resource

### Key Differences Between Languages

#### Java
- Uses verbose builder pattern
- Requires explicit exception handling with try-catch
- Traditional class structure

#### Kotlin
- More concise syntax with named parameters and string interpolation
- Better null safety with nullable types (`?`)
- Can use `try-catch` as expressions
- Cleaner lambda syntax

#### Scala
- Functional programming style with `Try` and `Option` monads
- Pattern matching with `recover`
- For-comprehensions for sequential operations (not shown in basic example)
- Immutable by default

## Running the Examples

These examples are meant to be copied into your own project. They demonstrate the API usage patterns but are not standalone runnable programs without:

1. A valid SpiceDB instance (local or cloud)
2. A valid authentication token
3. Proper build configuration for your language

## Getting Started

For a complete guide on integrating SpiceDB with your application, see the [Protecting Your First App](https://authzed.com/docs/guides/first-app) guide.

## Additional Resources

- [Authzed Java Client Documentation](https://authzed.github.io/authzed-java/index.html)
- [SpiceDB API Reference](https://authzed.com/docs/spicedb/api/http-api)
- [Buf Registry SpiceDB API](https://buf.build/authzed/api/docs/main)
- [SpiceDB Documentation](https://authzed.com/docs)
188 changes: 188 additions & 0 deletions examples/kotlin/CallingCheck.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
* Authzed API examples - Kotlin
*
* This example demonstrates how to use the Authzed Java client library from Kotlin.
* It shows the more idiomatic Kotlin syntax while using the same Java client library.
*/

import com.authzed.api.v1.*
import com.authzed.grpcutil.BearerToken
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
import java.util.concurrent.TimeUnit
import java.util.logging.Level
import java.util.logging.Logger

// Installation
// Add to your build.gradle.kts:
// dependencies {
// implementation("com.authzed.api:authzed:1.5.4")
// implementation("io.grpc:grpc-api:1.75.0")
// implementation("io.grpc:grpc-stub:1.75.0")
// implementation("io.grpc:grpc-netty-shaded:1.75.0")
// }

class AuthzedClient(channel: ManagedChannel, token: String) {
private val logger = Logger.getLogger(AuthzedClient::class.java.name)
private val bearerToken = BearerToken(token)

private val schemaService: SchemaServiceGrpc.SchemaServiceBlockingStub =
SchemaServiceGrpc.newBlockingStub(channel)
.withCallCredentials(bearerToken)

private val permissionsService: PermissionsServiceGrpc.PermissionsServiceBlockingStub =
PermissionsServiceGrpc.newBlockingStub(channel)
.withCallCredentials(bearerToken)

fun writeSchema(): String {
logger.info("Writing schema...")

val schema = """
definition thelargeapp/article {
relation author: thelargeapp/user
relation commenter: thelargeapp/user

permission can_comment = commenter + author
}

definition thelargeapp/user {}
""".trimIndent()

val request = WriteSchemaRequest.newBuilder()
.setSchema(schema)
.build()

return try {
val response = schemaService.writeSchema(request)
logger.info("Response: $response")
response.toString()
} catch (e: Exception) {
logger.log(Level.WARNING, "RPC failed: ${e.message}")
""
}
}

fun readSchema(): String {
logger.info("Reading schema...")

val request = ReadSchemaRequest.newBuilder().build()

return try {
val response = schemaService.readSchema(request)
logger.info(response.toString())
response.toString()
} catch (e: Exception) {
logger.log(Level.WARNING, "RPC failed: ${e.message}")
""
}
}

fun writeRelationship(): String {
logger.info("Write relationship...")

val request = WriteRelationshipsRequest.newBuilder()
.addUpdates(
RelationshipUpdate.newBuilder()
.setOperation(RelationshipUpdate.Operation.OPERATION_CREATE)
.setRelationship(
Relationship.newBuilder()
.setResource(
ObjectReference.newBuilder()
.setObjectType("thelargeapp/article")
.setObjectId("kotlin_test")
.build()
)
.setRelation("author")
.setSubject(
SubjectReference.newBuilder()
.setObject(
ObjectReference.newBuilder()
.setObjectType("thelargeapp/user")
.setObjectId("george")
.build()
)
.build()
)
.build()
)
.build()
)
.build()

return try {
val response = permissionsService.writeRelationships(request)
logger.info("Response: $response")
response.writtenAt.token
} catch (e: Exception) {
logger.log(Level.WARNING, "RPC failed: ${e.message}")
""
}
}

fun check(zedToken: ZedToken): CheckPermissionResponse.Permissionship? {
logger.info("Checking...")

val request = CheckPermissionRequest.newBuilder()
.setConsistency(
Consistency.newBuilder()
.setAtLeastAsFresh(zedToken)
.build()
)
.setResource(
ObjectReference.newBuilder()
.setObjectType("thelargeapp/article")
.setObjectId("kotlin_test")
.build()
)
.setSubject(
SubjectReference.newBuilder()
.setObject(
ObjectReference.newBuilder()
.setObjectType("thelargeapp/user")
.setObjectId("george")
.build()
)
.build()
)
.setPermission("can_comment")
.build()

return try {
val response = permissionsService.checkPermission(request)
logger.info("Response: $response")
response.permissionship
} catch (e: Exception) {
logger.log(Level.WARNING, "RPC failed: ${e.message}")
null
}
}
}

fun main() {
val target = "grpc.authzed.com:443"
val token = "tc_test_def_token"

val channel = ManagedChannelBuilder
.forTarget(target)
.useTransportSecurity() // for local development without TLS, use .usePlaintext()
.build()

try {
val client = AuthzedClient(channel, token)

client.writeSchema()
client.readSchema()

val tokenVal = client.writeRelationship()

val result = client.check(
ZedToken.newBuilder()
.setToken(tokenVal)
.build()
)

println("Check result: $result")
} finally {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS)
}
}
Loading