Hi Ory team, I use Ory Network (Kratos & Keto)...
# ory-network
w
Hi Ory team, I use Ory Network (Kratos & Keto). Could not find documentation how to connect with gRPC to check the permissions. Backend written in Go.
h
@steep-lamp-91158 can you show how it works?
👀 1
do we not have docs for this?
w
@steep-lamp-91158 @high-optician-2097
s
This is how we do it in our e2e tests in JS:
Copy code
const metaCallback: CallMetadataGenerator = (_, callback) => {
    const meta = new grpc.Metadata()
    if (token) {
      meta.add("authorization", "Bearer " + token)
    }
    callback(null, meta)
  }
  const callCreds = grpc.credentials.createFromMetadataGenerator(metaCallback)
so you basically just want to set the authorization header to
Bearer your_api_key
I'll add that to the docs
w
@steep-lamp-91158 I could not find an address to connect. What address/port should i use?
s
your project slug url
you find it under
Access & APIs
w
func testGRPC() {
conn, err := grpc.Dial("MY_ORY_ADDRESS:4467", grpc.WithInsecure(), grpc.WithUnaryInterceptor(authInterceptor("MY_ORY_TOKEN")))
if err != nil {
panic("Encountered error: " + err.Error())
}
fmt.Println("State: ", conn.GetState())
client := acl.NewWriteServiceClient(conn)
_, err = client.TransactRelationTuples(context.Background(), &acl.TransactRelationTuplesRequest{
RelationTupleDeltas: []*acl.RelationTupleDelta{
{
Action: acl.RelationTupleDelta_INSERT,
RelationTuple: &acl.RelationTuple{
Namespace: "messages",
Object:    "02y_15_4w350m3",
Relation:  "decypher",
Subject:   &acl.Subject{},
},
},
},
})
if err != nil {
panic("Encountered error: " + err.Error())
}
fmt.Println("Successfully created tuple")
}
func authInterceptor(accessToken string) grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
newCtx := metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+accessToken)
return invoker(newCtx, method, req, reply, cc, opts...)
}
}
@steep-lamp-91158 It's not working.
Error while dialing: dial tcp _IP_ADDRESS_:4467
are you using the ory proxy?
you probably just need to drop the port
w
No, I don't use proxy. Same without port.
s
the host should be something like
<http://elegant-nobel-fhv4ruffh9.projects.oryapis.com|elegant-nobel-fhv4ruffh9.projects.oryapis.com>
why the
grpc.WithInsecure
?
w
@steep-lamp-91158 idk, just trying everything. Could not find proper docs.
I'll check Ory CLI code
s
Copy code
package main

import (
	"context"
	"fmt"
	"<http://google.golang.org/grpc/credentials|google.golang.org/grpc/credentials>"
	"os"

	rts "<http://github.com/ory/keto/proto/ory/keto/relation_tuples/v1alpha2|github.com/ory/keto/proto/ory/keto/relation_tuples/v1alpha2>"
	"<http://google.golang.org/grpc|google.golang.org/grpc>"
	"<http://google.golang.org/grpc/metadata|google.golang.org/grpc/metadata>"
)

func main() {
	conn, err := grpc.Dial("<http://elegant-nobel-fhv4ruffh9.projects.oryapis.com:443|elegant-nobel-fhv4ruffh9.projects.oryapis.com:443>", grpc.WithTransportCredentials(credentials.NewTLS(nil)), grpc.WithAuthority("<http://elegant-nobel-fhv4ruffh9.projects.oryapis.com|elegant-nobel-fhv4ruffh9.projects.oryapis.com>"), grpc.WithUnaryInterceptor(authInterceptor(os.Getenv("ORY_API_KEY"))))
	if err != nil {
		panic("Encountered error: " + err.Error())
	}
	fmt.Println("State: ", conn.GetState())
	client := rts.NewWriteServiceClient(conn)
	_, err = client.TransactRelationTuples(context.Background(), &rts.TransactRelationTuplesRequest{
		RelationTupleDeltas: []*rts.RelationTupleDelta{
			{
				Action: rts.RelationTupleDelta_ACTION_INSERT,
				RelationTuple: &rts.RelationTuple{
					Namespace: "File",
					Object:    "foo",
					Relation:  "owner",
					Subject:   rts.NewSubjectSet("User", "john", ""),
				},
			},
		},
	})
	if err != nil {
		panic("Encountered error: " + err.Error())
	}
	fmt.Println("Successfully created tuple")
}

func authInterceptor(accessToken string) grpc.UnaryClientInterceptor {
	return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		newCtx := metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+accessToken)
		return invoker(newCtx, method, req, reply, cc, opts...)
	}
}
This worked for me, maybe you used an old version of the grpc client?
also make sure to create the namespaces
grpc.WithAuthority
is not needed
w
ok let me try
it works! it seems problem was with
grpc.WithTransportCredentials(credentials.NewTLS(nil))
Thanks. Probably it's good to add somewhere in the documentation, or i'll make PR later to Ory Doc. Thanks!
s
It would be awesome if you could raise a PR ❤️
❇️ 1
w
@steep-lamp-91158 I'm getting this result:
snaptoken:"not yet implemented"
with this code below, what might be wrong?
Copy code
res, err := check.Check(ctx, &rts.CheckRequest{
        Namespace: "LegalEntity",
        Object:    "entity1",
        Relation:  "readers",
        Tuple: &rts.RelationTuple{
            Namespace: "User",
            Subject: &rts.Subject{
                Ref: &rts.Subject_Id{
                    Id: "<mailto:[email protected]|[email protected]>",
                },
            },
        },
    })
s
That is perfectly fine
You should either set the fields in the tuple, or on the root, but not both
w
gotcha, but strange, it returns Allowed: False, but everything seems correct.
s
Move all the fields to the tuple field and try again
And use the subject set without a relation for subjects with namespaces
w
Copy code
Tuple: &rts.RelationTuple{
    Namespace: "LegalEntity",
    Object:    "entity1",
    Relation:  "readers",
    Subject: &rts.Subject{
        Ref: &rts.Subject_Set{
            Set: &rts.SubjectSet{
                Namespace: "User",
                Object:    "<mailto:[email protected]|[email protected]>",
            },
        },
    },
},
Okay, this works fine!
s
Nice
w
But is it correct way to communicate? Do you suggest any best/common practices?
s
There is also a helper to create the subjects btw
And yeah, that's correct
👍 1
w
okay thanks!
is it safe to communicate without proxy?
s
Yes the proxy is only for host rewrites for browser stuff