forked from mystiq/dex
commit
1d892c6cac
12 changed files with 2015 additions and 45 deletions
|
@ -1,47 +1,50 @@
|
|||
# The dex API
|
||||
# The Dex API
|
||||
|
||||
Dex provides a [gRPC][grpc] service for programmatic modification of dex's state. The API is intended to expose hooks for management applications and is not expected to be used by most installations.
|
||||
Dex provides a [gRPC](http://www.grpc.io/) service for programmatic modification of dex's state.
|
||||
The API is intended to expose hooks for management applications and is not expected to be used by most installations.
|
||||
|
||||
This document is an overview of how to interact with the API.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
Admins that wish to expose the gRPC service must add the following entry to the dex config file. This option is off by default.
|
||||
|
||||
```
|
||||
```yaml
|
||||
grpc:
|
||||
# Cannot be the same address as an HTTP(S) service.
|
||||
addr: 127.0.0.1:5557
|
||||
|
||||
# Server certs. If TLS credentials aren't provided dex will run in plaintext (HTTP) mode.
|
||||
tlsCert: /etc/dex/grpc.crt
|
||||
tlsKey: /etc/dex/grpc.key
|
||||
|
||||
# Client auth CA.
|
||||
tlsClientCA: /etc/dex/client.crt
|
||||
|
||||
# enable reflection
|
||||
reflection: true
|
||||
```
|
||||
|
||||
## Generating clients
|
||||
|
||||
gRPC is a suite of tools for generating client and server bindings from a common declarative language. The canonical schema for dex's API can be found in the source tree at [`api/api.proto`][api-proto]. Go bindings are generated and maintained in the same directory for internal use.
|
||||
## Clients
|
||||
|
||||
To generate a client for your own project install [`protoc`][protoc], install a protobuf generator for your project's language, and download the `api.proto` file. An example for a Go project:
|
||||
gRPC is a suite of tools for generating client and server bindings from a common declarative language.
|
||||
The canonical schema for Dex's API can be found in the source tree at [`api/v2/api.proto`](../api/v2/api.proto).
|
||||
Go bindings are generated and maintained in the same directory for both public and internal use.
|
||||
|
||||
```
|
||||
# Install protoc-gen-go.
|
||||
$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
|
||||
|
||||
# Download api.proto for a given version.
|
||||
$ DEX_VERSION=v2.0.0-alpha.5
|
||||
$ wget https://raw.githubusercontent.com/dexidp/dex/${DEX_VERSION}/api/api.proto
|
||||
### Go
|
||||
|
||||
# Generate the Go client bindings.
|
||||
$ protoc --go_out=import_path=dexapi:. api.proto
|
||||
A Go project can import the API module directly, without having to import the entire project:
|
||||
|
||||
```bash
|
||||
go get github.com/dexidp/dex/api/v2
|
||||
```
|
||||
|
||||
Client programs can then be written using the generated code. A Go client which uses dex's internally generated code might look like the following:
|
||||
The client then can be used as follows:
|
||||
|
||||
```
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -49,7 +52,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/dexidp/dex/api"
|
||||
"github.com/dexidp/dex/api/v2"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
@ -88,30 +91,56 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
A clear working example of the Dex gRPC client can be found [here](../examples/grpc-client/README.md).
|
||||
A clear working example of the Dex gRPC client for Go can be found [here](../examples/grpc-client/README.md).
|
||||
|
||||
|
||||
### Other languages
|
||||
|
||||
To generate a client for your own project install [`protoc`](https://github.com/google/protobuf/releases),
|
||||
install a protobuf generator for your project's language, and download the `api.proto` file.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```bash
|
||||
# Download api.proto for a given version.
|
||||
$ DEX_VERSION=v2.24.0
|
||||
$ wget https://raw.githubusercontent.com/dexidp/dex/${DEX_VERSION}/api/v2/api.proto
|
||||
|
||||
# Generate the client bindings.
|
||||
$ protoc [YOUR LANG PARAMS] api.proto
|
||||
```
|
||||
|
||||
Client programs can then be written using the generated code.
|
||||
|
||||
|
||||
## Authentication and access control
|
||||
|
||||
The dex API does not provide any authentication or authorization beyond TLS client auth.
|
||||
The Dex API does not provide any authentication or authorization beyond TLS client auth.
|
||||
|
||||
Projects that wish to add access controls on top of the existing API should build apps which perform such checks.
|
||||
For example to provide a "Change password" screen, a client app could use Dex's OpenID Connect flow to authenticate an end user,
|
||||
then call Dex's API to update that user's password.
|
||||
|
||||
Projects that wish to add access controls on top of the existing API should build apps which perform such checks. For example to provide a "Change password" screen, a client app could use dex's OpenID Connect flow to authenticate an end user, then call dex's API to update that user's password.
|
||||
|
||||
## dexctl?
|
||||
|
||||
Dex does not ship with a command line tool for interacting with the API. Command line tools are useful but hard to version, easy to design poorly, and expose another interface which can never be changed in the name of compatibility.
|
||||
Dex does not ship with a command line tool for interacting with the API.
|
||||
Command line tools are useful but hard to version, easy to design poorly,
|
||||
and expose another interface which can never be changed in the name of compatibility.
|
||||
|
||||
While the Dex team would be open to re-implementing `dexctl` for v2 a majority of the work is writing a design document,
|
||||
not the actual programming effort.
|
||||
|
||||
While the dex team would be open to re-implementing `dexctl` for v2 a majority of the work is writing a design document, not the actual programming effort.
|
||||
|
||||
## Why not REST or gRPC Gateway?
|
||||
|
||||
Between v1 and v2, dex switched from REST to gRPC. This largely stemmed from problems generating documentation, client bindings, and server frameworks that adequately expressed REST semantics. While [Google APIs][google-apis], [Open API/Swagger][open-api], and [gRPC Gateway][grpc-gateway] were evaluated, they often became clunky when trying to use specific HTTP error codes or complex request bodies. As a result, v2's API is entirely gRPC.
|
||||
Between v1 and v2, Dex switched from REST to gRPC. This largely stemmed from problems generating documentation,
|
||||
client bindings, and server frameworks that adequately expressed REST semantics.
|
||||
While [Google APIs](https://github.com/google/apis-client-generator), [Open API/Swagger](https://openapis.org/),
|
||||
and [gRPC Gateway](https://github.com/grpc-ecosystem/grpc-gateway) were evaluated,
|
||||
they often became clunky when trying to use specific HTTP error codes or complex request bodies.
|
||||
As a result, v2's API is entirely gRPC.
|
||||
|
||||
Many arguments _against_ gRPC cite short term convenience rather than production use cases. Though this is a recognized shortcoming, dex already implements many features for developer convenience. For instance, users who wish to manually edit clients during testing can use the `staticClients` config field instead of the API.
|
||||
|
||||
[grpc]: http://www.grpc.io/
|
||||
[api-proto]: ../api/api.proto
|
||||
[protoc]: https://github.com/google/protobuf/releases
|
||||
[protoc-gen-go]: https://github.com/golang/protobuf
|
||||
[google-apis]: https://github.com/google/apis-client-generator
|
||||
[open-api]: https://openapis.org/
|
||||
[grpc-gateway]: https://github.com/grpc-ecosystem/grpc-gateway
|
||||
Many arguments _against_ gRPC cite short term convenience rather than production use cases.
|
||||
Though this is a recognized shortcoming, Dex already implements many features for developer convenience.
|
||||
For instance, users who wish to manually edit clients during testing can use the `staticClients` config field instead of the API.
|
||||
|
|
2
Makefile
2
Makefile
|
@ -74,6 +74,8 @@ docker-image:
|
|||
|
||||
.PHONY: proto
|
||||
proto: bin/protoc bin/protoc-gen-go
|
||||
@./bin/protoc --go_out=plugins=grpc:. --plugin=protoc-gen-go=./bin/protoc-gen-go api/v2/*.proto
|
||||
@cp api/v2/*.proto api/
|
||||
@./bin/protoc --go_out=plugins=grpc:. --plugin=protoc-gen-go=./bin/protoc-gen-go api/*.proto
|
||||
@./bin/protoc --go_out=. --plugin=protoc-gen-go=./bin/protoc-gen-go server/internal/*.proto
|
||||
|
||||
|
|
1758
api/v2/api.pb.go
Normal file
1758
api/v2/api.pb.go
Normal file
File diff suppressed because it is too large
Load diff
187
api/v2/api.proto
Normal file
187
api/v2/api.proto
Normal file
|
@ -0,0 +1,187 @@
|
|||
syntax = "proto3";
|
||||
option java_package = "com.coreos.dex.api";
|
||||
|
||||
package api;
|
||||
|
||||
// Client represents an OAuth2 client.
|
||||
message Client {
|
||||
string id = 1;
|
||||
string secret = 2;
|
||||
repeated string redirect_uris = 3;
|
||||
repeated string trusted_peers = 4;
|
||||
bool public = 5;
|
||||
string name = 6;
|
||||
string logo_url = 7;
|
||||
}
|
||||
|
||||
// CreateClientReq is a request to make a client.
|
||||
message CreateClientReq {
|
||||
Client client = 1;
|
||||
}
|
||||
|
||||
// CreateClientResp returns the response from creating a client.
|
||||
message CreateClientResp {
|
||||
bool already_exists = 1;
|
||||
Client client = 2;
|
||||
}
|
||||
|
||||
// DeleteClientReq is a request to delete a client.
|
||||
message DeleteClientReq {
|
||||
// The ID of the client.
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
// DeleteClientResp determines if the client is deleted successfully.
|
||||
message DeleteClientResp {
|
||||
bool not_found = 1;
|
||||
}
|
||||
|
||||
// UpdateClientReq is a request to update an exisitng client.
|
||||
message UpdateClientReq {
|
||||
string id = 1;
|
||||
repeated string redirect_uris = 2;
|
||||
repeated string trusted_peers = 3;
|
||||
string name = 4;
|
||||
string logo_url = 5;
|
||||
}
|
||||
|
||||
// UpdateClientResp returns the reponse form updating a client.
|
||||
message UpdateClientResp {
|
||||
bool not_found = 1;
|
||||
}
|
||||
|
||||
// TODO(ericchiang): expand this.
|
||||
|
||||
// Password is an email for password mapping managed by the storage.
|
||||
message Password {
|
||||
string email = 1;
|
||||
|
||||
// Currently we do not accept plain text passwords. Could be an option in the future.
|
||||
bytes hash = 2;
|
||||
string username = 3;
|
||||
string user_id = 4;
|
||||
}
|
||||
|
||||
// CreatePasswordReq is a request to make a password.
|
||||
message CreatePasswordReq {
|
||||
Password password = 1;
|
||||
}
|
||||
|
||||
// CreatePasswordResp returns the response from creating a password.
|
||||
message CreatePasswordResp {
|
||||
bool already_exists = 1;
|
||||
}
|
||||
|
||||
// UpdatePasswordReq is a request to modify an existing password.
|
||||
message UpdatePasswordReq {
|
||||
// The email used to lookup the password. This field cannot be modified
|
||||
string email = 1;
|
||||
bytes new_hash = 2;
|
||||
string new_username = 3;
|
||||
}
|
||||
|
||||
// UpdatePasswordResp returns the response from modifying an existing password.
|
||||
message UpdatePasswordResp {
|
||||
bool not_found = 1;
|
||||
}
|
||||
|
||||
// DeletePasswordReq is a request to delete a password.
|
||||
message DeletePasswordReq {
|
||||
string email = 1;
|
||||
}
|
||||
|
||||
// DeletePasswordResp returns the response from deleting a password.
|
||||
message DeletePasswordResp {
|
||||
bool not_found = 1;
|
||||
}
|
||||
|
||||
// ListPasswordReq is a request to enumerate passwords.
|
||||
message ListPasswordReq {}
|
||||
|
||||
// ListPasswordResp returns a list of passwords.
|
||||
message ListPasswordResp {
|
||||
repeated Password passwords = 1;
|
||||
}
|
||||
|
||||
// VersionReq is a request to fetch version info.
|
||||
message VersionReq {}
|
||||
|
||||
// VersionResp holds the version info of components.
|
||||
message VersionResp {
|
||||
// Semantic version of the server.
|
||||
string server = 1;
|
||||
// Numeric version of the API. It increases everytime a new call is added to the API.
|
||||
// Clients should use this info to determine if the server supports specific features.
|
||||
int32 api = 2;
|
||||
}
|
||||
|
||||
// RefreshTokenRef contains the metadata for a refresh token that is managed by the storage.
|
||||
message RefreshTokenRef {
|
||||
// ID of the refresh token.
|
||||
string id = 1;
|
||||
string client_id = 2;
|
||||
int64 created_at = 5;
|
||||
int64 last_used = 6;
|
||||
}
|
||||
|
||||
// ListRefreshReq is a request to enumerate the refresh tokens of a user.
|
||||
message ListRefreshReq {
|
||||
// The "sub" claim returned in the ID Token.
|
||||
string user_id = 1;
|
||||
}
|
||||
|
||||
// ListRefreshResp returns a list of refresh tokens for a user.
|
||||
message ListRefreshResp {
|
||||
repeated RefreshTokenRef refresh_tokens = 1;
|
||||
}
|
||||
|
||||
// RevokeRefreshReq is a request to revoke the refresh token of the user-client pair.
|
||||
message RevokeRefreshReq {
|
||||
// The "sub" claim returned in the ID Token.
|
||||
string user_id = 1;
|
||||
string client_id = 2;
|
||||
}
|
||||
|
||||
// RevokeRefreshResp determines if the refresh token is revoked successfully.
|
||||
message RevokeRefreshResp {
|
||||
// Set to true is refresh token was not found and token could not be revoked.
|
||||
bool not_found = 1;
|
||||
}
|
||||
|
||||
message VerifyPasswordReq {
|
||||
string email = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
message VerifyPasswordResp {
|
||||
bool verified = 1;
|
||||
bool not_found = 2;
|
||||
}
|
||||
|
||||
// Dex represents the dex gRPC service.
|
||||
service Dex {
|
||||
// CreateClient creates a client.
|
||||
rpc CreateClient(CreateClientReq) returns (CreateClientResp) {};
|
||||
// UpdateClient updates an existing client
|
||||
rpc UpdateClient(UpdateClientReq) returns (UpdateClientResp) {};
|
||||
// DeleteClient deletes the provided client.
|
||||
rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
|
||||
// CreatePassword creates a password.
|
||||
rpc CreatePassword(CreatePasswordReq) returns (CreatePasswordResp) {};
|
||||
// UpdatePassword modifies existing password.
|
||||
rpc UpdatePassword(UpdatePasswordReq) returns (UpdatePasswordResp) {};
|
||||
// DeletePassword deletes the password.
|
||||
rpc DeletePassword(DeletePasswordReq) returns (DeletePasswordResp) {};
|
||||
// ListPassword lists all password entries.
|
||||
rpc ListPasswords(ListPasswordReq) returns (ListPasswordResp) {};
|
||||
// GetVersion returns version information of the server.
|
||||
rpc GetVersion(VersionReq) returns (VersionResp) {};
|
||||
// ListRefresh lists all the refresh token entries for a particular user.
|
||||
rpc ListRefresh(ListRefreshReq) returns (ListRefreshResp) {};
|
||||
// RevokeRefresh revokes the refresh token for the provided user-client pair.
|
||||
//
|
||||
// Note that each user-client pair can have only one refresh token at a time.
|
||||
rpc RevokeRefresh(RevokeRefreshReq) returns (RevokeRefreshResp) {};
|
||||
// VerifyPassword returns whether a password matches a hash for a specific email or not.
|
||||
rpc VerifyPassword(VerifyPasswordReq) returns (VerifyPasswordResp) {};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
module github.com/dexidp/dex/api
|
||||
module github.com/dexidp/dex/api/v2
|
||||
|
||||
go 1.14
|
||||
|
|
@ -23,7 +23,7 @@ import (
|
|||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/reflection"
|
||||
|
||||
"github.com/dexidp/dex/api"
|
||||
"github.com/dexidp/dex/api/v2"
|
||||
"github.com/dexidp/dex/pkg/log"
|
||||
"github.com/dexidp/dex/server"
|
||||
"github.com/dexidp/dex/storage"
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
||||
"github.com/dexidp/dex/api"
|
||||
"github.com/dexidp/dex/api/v2"
|
||||
)
|
||||
|
||||
func newDexClient(hostAndPort, caPath, clientCrt, clientKey string) (api.DexClient, error) {
|
||||
|
|
6
go.mod
6
go.mod
|
@ -9,7 +9,7 @@ require (
|
|||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
|
||||
github.com/dexidp/dex/api v0.0.0-00010101000000-000000000000
|
||||
github.com/dexidp/dex/api/v2 v2.0.0-00010101000000-000000000000
|
||||
github.com/felixge/httpsnoop v1.0.1
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
|
@ -35,11 +35,9 @@ require (
|
|||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738
|
||||
go.uber.org/atomic v1.4.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
|
||||
golang.org/x/tools v0.0.0-20190813214729-9dba7caff850 // indirect
|
||||
google.golang.org/api v0.15.0
|
||||
google.golang.org/appengine v1.6.1 // indirect
|
||||
google.golang.org/grpc v1.26.0
|
||||
|
@ -49,4 +47,4 @@ require (
|
|||
sigs.k8s.io/testing_frameworks v0.1.2
|
||||
)
|
||||
|
||||
replace github.com/dexidp/dex/api => ./api
|
||||
replace github.com/dexidp/dex/api/v2 => ./api/v2
|
||||
|
|
4
go.sum
4
go.sum
|
@ -336,7 +336,6 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -392,9 +391,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190813214729-9dba7caff850 h1:I+2i9HEjvv+3iJrNMhjMJOMF/FXz9eI08iBlDF4w24I=
|
||||
golang.org/x/tools v0.0.0-20190813214729-9dba7caff850/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/dexidp/dex/api"
|
||||
"github.com/dexidp/dex/api/v2"
|
||||
"github.com/dexidp/dex/pkg/log"
|
||||
"github.com/dexidp/dex/server/internal"
|
||||
"github.com/dexidp/dex/storage"
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/dexidp/dex/api"
|
||||
"github.com/dexidp/dex/api/v2"
|
||||
"github.com/dexidp/dex/pkg/log"
|
||||
"github.com/dexidp/dex/server/internal"
|
||||
"github.com/dexidp/dex/storage"
|
||||
|
|
Loading…
Reference in a new issue