1、use docker-machine create vm get ip: 192.168.99.100

2、deploy
https://www.ory.sh/docs/next/hydra/configure-deploy

  
docker network create hydraguide  

  
docker run \  
  --network hydraguide \  
  --name ory-hydra-example--postgres \  
  -e POSTGRES_USER=hydra \  
  -e POSTGRES_PASSWORD=secret \  
  -e POSTGRES_DB=hydra \  
  -d postgres:9.6  

  
export SECRETS_SYSTEM=this_needs_to_be_the_same_always_and_also_very_$3cuR3-._  
  
export DSN=postgres://hydra:secret@ory-hydra-example--postgres:5432/hydra?sslmode=disable  
  
docker pull oryd/hydra:latest  

  
docker run -it --rm \  
  --network hydraguide \  
  oryd/hydra:latest \  
  migrate sql --yes $DSN  

=====creat ssl cert and key====
!!注意!! 產生方式改用 https://sueboy.blogspot.com/2019/08/openssl-self-signed-certificate.html 較為保險,不容易發生 ERR_SSL_VERSION_OR_CIPHER_MISMATCH 錯誤!

create two cert. 1. t.tt 2. openid.hydra

  
In vm  
openssl genrsa -out t.tt.key 2048  
openssl ecparam -genkey -name secp384r1 -out t.tt.key  
openssl req -new -x509 -sha256 -key t.tt.key -out t.tt.crt -days 3650  
Important!! t.tt.crt step: Common Name (e.g. server FQDN or YOUR name) []: t.tt  
  
  
openssl genrsa -out openid.hydra.key 2048  
openssl ecparam -genkey -name secp384r1 -out openid.hydra.key  
openssl req -new -x509 -sha256 -key openid.hydra.key -out openid.hydra.crt -days 3650  
Important!! openid.hydra.crt step: Common Name (e.g. server FQDN or YOUR name) []: openid.hydra  

Use openid.hydra.key and openid.hydra.crt to base64 code
https://www.base64encode.org/

openid.hydra.key

-—-BEGIN EC PARAMETERS—–
BgUrgQQAIg==
-—-END EC PARAMETERS—–
-—-BEGIN EC PRIVATE KEY—–
MIGkAgEBBDCKnGgVqIW7YinbQeyPGyQ44Gu6UQDzU9HCKb33MifxRXE0dnu6+7Zu
0tBTqHPDuLygBwYFK4EEACKhZANiAARnx56OcxcrEdlbe8MtRuEqXev8DDrhzebF
386R8CdPX4eQb6fYzzAT/uwI0lL7oFiDXC7CBKZfTq7EK3xO3WZZRJ2k0D7NsKwg
TJYzrqOBis0MxkokaTYUrzhJ1pJcyfY=
-—-END EC PRIVATE KEY—–

openid.hydra.crt

-—-BEGIN CERTIFICATE—–
MIICPTCCAcKgAwIBAgIJAMwF4bT4oJxtMAoGCCqGSM49BAMCMFwxCzAJBgNVBAYT
AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
aXRzIFB0eSBMdGQxFTATBgNVBAMMDG9wZW5pZC5oeWRyYTAeFw0xOTA2MTcwMTIx
MzdaFw0yOTA2MTQwMTIxMzdaMFwxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l
LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNV
BAMMDG9wZW5pZC5oeWRyYTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGfHno5zFysR
2Vt7wy1G4Spd6/wMOuHN5sXfzpHwJ09fh5Bvp9jPMBP+7AjSUvugWINcLsIEpl9O
rsQrfE7dZllEnaTQPs2wrCBMljOuo4GKzQzGSiRpNhSvOEnWklzJ9qNQME4wHQYD
VR0OBBYEFG+vzfB1beg3UZtJXEvV9dMkXo6gMB8GA1UdIwQYMBaAFG+vzfB1beg3
UZtJXEvV9dMkXo6gMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDaQAwZgIxALPv
86EHTTTIKpBGvT+ccV7wcH/8HR+slad/YPXKRVpwdCo52eTOWpCKgFjkG4BawQIx
ALlFdX0lI6g8WKyaE5f+2FdI1aejCAmwLOM6SDRa4UGn+Ckep8IcxmBL2/Be3IVz
8g==
-—-END CERTIFICATE—–

SERVE_TLS_KEY_BASE64=LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJZz09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUlHa0FnRUJCRENLbkdnVnFJVzdZaW5iUWV5UEd5UTQ0R3U2VVFEelU5SENLYjMzTWlmeFJYRTBkbnU2KzdadQowdEJUcUhQRHVMeWdCd1lGSzRFRUFDS2haQU5pQUFSbng1Nk9jeGNyRWRsYmU4TXRSdUVxWGV2OEREcmh6ZWJGCjM4NlI4Q2RQWDRlUWI2Zll6ekFUL3V3STBsTDdvRmlEWEM3Q0JLWmZUcTdFSzN4TzNXWlpSSjJrMEQ3TnNLd2cKVEpZenJxT0JpczBNeGtva2FUWVVyemhKMXBKY3lmWT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=

SERVE_TLS_CERT_BASE64=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQVENDQWNLZ0F3SUJBZ0lKQU13RjRiVDRvSnh0TUFvR0NDcUdTTTQ5QkFNQ01Gd3hDekFKQmdOVkJBWVQKQWtGVk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbgphWFJ6SUZCMGVTQk1kR1F4RlRBVEJnTlZCQU1NREc5d1pXNXBaQzVvZVdSeVlUQWVGdzB4T1RBMk1UY3dNVEl4Ck16ZGFGdzB5T1RBMk1UUXdNVEl4TXpkYU1Gd3hDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWwKTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhGVEFUQmdOVgpCQU1NREc5d1pXNXBaQzVvZVdSeVlUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkdmSG5vNXpGeXNSCjJWdDd3eTFHNFNwZDYvd01PdUhONXNYZnpwSHdKMDlmaDVCdnA5alBNQlArN0FqU1V2dWdXSU5jTHNJRXBsOU8KcnNRcmZFN2RabGxFbmFUUVBzMndyQ0JNbGpPdW80R0t6UXpHU2lScE5oU3ZPRW5Xa2x6SjlxTlFNRTR3SFFZRApWUjBPQkJZRUZHK3Z6ZkIxYmVnM1VadEpYRXZWOWRNa1hvNmdNQjhHQTFVZEl3UVlNQmFBRkcrdnpmQjFiZWczClVadEpYRXZWOWRNa1hvNmdNQXdHQTFVZEV3UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURhUUF3WmdJeEFMUHYKODZFSFRUVElLcEJHdlQrY2NWN3djSC84SFIrc2xhZC9ZUFhLUlZwd2RDbzUyZVRPV3BDS2dGamtHNEJhd1FJeApBTGxGZFgwbEk2ZzhXS3lhRTVmKzJGZEkxYWVqQ0Ftd0xPTTZTRFJhNFVHbitDa2VwOEljeG1CTDIvQmUzSVZ6CjhnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=

  
docker run -d \  
  --name ory-hydra-example--hydra \  
  --network hydraguide \  
  -p 9001:4444 \  
  -p 9002:4445 \  
  -e SECRETS_SYSTEM=$SECRETS_SYSTEM \  
  -e DSN=$DSN \  
  -e URLS_SELF_ISSUER=https://openid.hydra:9001/ \  
  -e URLS_CONSENT=http://192.168.99.100:9020/consent \  
  -e URLS_LOGIN=http://192.168.99.100:9020/login \  
  -e LOG_LEVEL=debug \  
  -e OAUTH2_EXPOSE_INTERNAL_ERRORS=1 \  
  -e SERVE_PUBLIC_CORS_ENABLED=true \  
  -e SERVE_PUBLIC_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE \  
  -e SERVE_ADMIN_CORS_ENABLED=true \  
  -e SERVE_ADMIN_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE \  
  -e SERVE_TLS_KEY_BASE64=LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJZz09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUlHa0FnRUJCRENLbkdnVnFJVzdZaW5iUWV5UEd5UTQ0R3U2VVFEelU5SENLYjMzTWlmeFJYRTBkbnU2KzdadQowdEJUcUhQRHVMeWdCd1lGSzRFRUFDS2haQU5pQUFSbng1Nk9jeGNyRWRsYmU4TXRSdUVxWGV2OEREcmh6ZWJGCjM4NlI4Q2RQWDRlUWI2Zll6ekFUL3V3STBsTDdvRmlEWEM3Q0JLWmZUcTdFSzN4TzNXWlpSSjJrMEQ3TnNLd2cKVEpZenJxT0JpczBNeGtva2FUWVVyemhKMXBKY3lmWT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= \  
  -e SERVE_TLS_CERT_BASE64=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQVENDQWNLZ0F3SUJBZ0lKQU13RjRiVDRvSnh0TUFvR0NDcUdTTTQ5QkFNQ01Gd3hDekFKQmdOVkJBWVQKQWtGVk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbgphWFJ6SUZCMGVTQk1kR1F4RlRBVEJnTlZCQU1NREc5d1pXNXBaQzVvZVdSeVlUQWVGdzB4T1RBMk1UY3dNVEl4Ck16ZGFGdzB5T1RBMk1UUXdNVEl4TXpkYU1Gd3hDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWwKTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhGVEFUQmdOVgpCQU1NREc5d1pXNXBaQzVvZVdSeVlUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkdmSG5vNXpGeXNSCjJWdDd3eTFHNFNwZDYvd01PdUhONXNYZnpwSHdKMDlmaDVCdnA5alBNQlArN0FqU1V2dWdXSU5jTHNJRXBsOU8KcnNRcmZFN2RabGxFbmFUUVBzMndyQ0JNbGpPdW80R0t6UXpHU2lScE5oU3ZPRW5Xa2x6SjlxTlFNRTR3SFFZRApWUjBPQkJZRUZHK3Z6ZkIxYmVnM1VadEpYRXZWOWRNa1hvNmdNQjhHQTFVZEl3UVlNQmFBRkcrdnpmQjFiZWczClVadEpYRXZWOWRNa1hvNmdNQXdHQTFVZEV3UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURhUUF3WmdJeEFMUHYKODZFSFRUVElLcEJHdlQrY2NWN3djSC84SFIrc2xhZC9ZUFhLUlZwd2RDbzUyZVRPV3BDS2dGamtHNEJhd1FJeApBTGxGZFgwbEk2ZzhXS3lhRTVmKzJGZEkxYWVqQ0Ftd0xPTTZTRFJhNFVHbitDa2VwOEljeG1CTDIvQmUzSVZ6CjhnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= \  
  oryd/hydra:latest serve all  

```LOG\_LEVEL ~ SERVE\_ADMIN\_CORS\_ALLOWED\_METHODS not important, add by yourself.  
  
  

docker run -d \
–name ory-hydra-example–consent \
-p 9020:3000 \
–network hydraguide \
-e HYDRA_ADMIN_URL=https://ory-hydra-example–hydra:4445 \
-e NODE_TLS_REJECT_UNAUTHORIZED=0 \
oryd/hydra-login-consent-node:latest

  

docker run –rm -it \
-e HYDRA_ADMIN_URL=https://ory-hydra-example–hydra:4445 \
–network hydraguide \
oryd/hydra:latest \
clients create –skip-tls-verify \
–id auth-code-client \
–secret secret \
–grant-types authorization_code,refresh_token \
–response-types token,code,id_token \
–scope openid,offline,photos.read \
–callbacks https://t.tt:9010/callback

All become http. So last step can callback use http. This production way only use https. And token user only http. So use self OpenID client.  
  
  

1\. nano /etc/hosts or windows hosts
------------------------------------

### 127.0.0.1 t.tt

### 192.168.99.100 openid.hydra

  

2\. use golang OpenID client + ssl
----------------------------------

https://blog.csdn.net/wangshubo1989/article/details/77980316  
https://github.com/denji/golang-tls  
  
  

### copy t.tt.key and t.tt.crt to go project

  
  

### main.go

package main

import (
“context”
“crypto/tls”
“fmt”
“log”
“net/http”
“strings”

“golang.org/x/oauth2”
)

const htmlIndex = `

var HydraOauthConfig = &oauth2.Config{
ClientID: “auth-code-client”,
ClientSecret: “secret”,
RedirectURL: “https://t.tt:9010/callback",
Scopes: []string{“openid”, “offline”, “photos.read”},
Endpoint: endpotin,
}

const oauthStateString = “gczxkznmjkrksgytsemvwgkf”

func main() {
http.HandleFunc("/”, handleMain)
http.HandleFunc("/HydraLogin", handleHydraLogin)
http.HandleFunc("/callback", handleCallback)
//fmt.Println(http.ListenAndServe(":9010", nil))
err := http.ListenAndServeTLS(":9010", “t.tt.crt”, “t.tt.key”, nil)
if err != nil {
log.Fatal(“ListenAndServe: “, err)
}
}

func handleMain(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, htmlIndex)
}

func handleHydraLogin(w http.ResponseWriter, r *http.Request) {
url := HydraOauthConfig.AuthCodeURL(oauthStateString)
log.Println(url)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}

func handleCallback(w http.ResponseWriter, r *http.Request) {
// add transport for self-signed certificate to context
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
sslcli := &http.Client{Transport: tr}
ctx := context.TODO()
ctx = context.WithValue(ctx, oauth2.HTTPClient, sslcli)

state := r.FormValue(“state”)
if state != oauthStateString {
log.Printf(“invalid oauth state, expected ‘%s’, got ‘%s’\n”, oauthStateString, state)
http.Redirect(w, r, “/”, http.StatusTemporaryRedirect)
return
}
log.Println(“state:”, state)

code := r.FormValue(“code”)
log.Println(“code: “, code)
token, err := HydraOauthConfig.Exchange(ctx, code)
if err != nil {
log.Println(“Code exchange failed with:”, err)
http.Redirect(w, r, “/”, http.StatusTemporaryRedirect)
return
}

TokenMsg := “Token Info
TokenMsg += fmt.Sprintf(“token.AccessToken : %s \n”, token.AccessToken)
TokenMsg += fmt.Sprintf(“token.TokenType : %s \n”, token.TokenType)
TokenMsg += fmt.Sprintf(“token.RefreshToken : %s \n”, token.RefreshToken)
TokenMsg += fmt.Sprintf(“token.Expiry : %s \n”, token.Expiry)
TokenMsg += fmt.Sprintf(“token Exra id_token : %s \n”, token.Extra(“id_token”))
TokenMsg += fmt.Sprintf(“token Exra scope : %s \n”, token.Extra(“scope”))

log.Println(TokenMsg)

log.Println("===========all token==========")
log.Println(“token: “, token)

log.Println(“Authentication token…. “)
client := HydraOauthConfig.Client(ctx, token)
resp, err := client.Get(“https://openid.hydra:9001/")
if err != nil {
log.Println(err)
} else {
log.Println(“Authentication successful !!")
}
defer resp.Body.Close()

// show succes page
msg := “Success!
msg += “You are authenticated and can now return to the CLI.
msg += strings.ReplaceAll(TokenMsg, “\n”, “")

fmt.Fprintf(w, msg)

//response, err := http.Get(“https://openid.hydra:9001/userinfo?access_token=" + token.AccessToken)
//defer response.Body.Close()
//contents, err := ioutil.ReadAll(response.Body)
//fmt.Fprintf(w, “Content: %s\n”, contents)
}


### Try https://t.tt Now can run finish all step.

  

[![](https://1.bp.blogspot.com/-mcLuuH9ZxbE/XQbywZJ8pxI/AAAAAAAAVOY/SggHb3krgJQ6LIeUp7bYrhS1XHQM81ZmACLcBGAs/s640/123123123.jpg)](https://1.bp.blogspot.com/-mcLuuH9ZxbE/XQbywZJ8pxI/AAAAAAAAVOY/SggHb3krgJQ6LIeUp7bYrhS1XHQM81ZmACLcBGAs/s1600/123123123.jpg)

  
hydra.rest  

@audience = audience=
@max_age = max_age=0
@nonce = nonce=kwhqocyluutsstfouosxluqc
@prompt = prompt=

@response_type = response_type=code
@state = state=gczxkznmjkrksgytsemvwgkf

@client_id = client_id=auth-code-client
@scope = scope=openid+offline+photos.read
@redirect_url = redirect_url=https%3A%2F%2Ft.tt%3A9010%2Fcallback

@auth-tailpart = {{audience}}&{{max_age}}&{{nonce}}&{{prompt}}
@9001_auth = https://openid.hydra:9001/oauth2/auth?

get hydra login page

Get {{9001_auth}}&{{client_id}}&{{redirect_url}}&{{scope}}&{{response_type}}&{{state}}&{{auth-tailpart}}

//提醒:csrf可以不更新,challenge一定要更新
@9020_login = http://192.168.99.100:9020/login
@9020_consent = http://192.168.99.100:9020/consent
@_csrf1 = Gxa6Hip4-J_A3L2kpRc72Iclw_Ql8eIcQiTc
@login_challenge = bc55b64985f1400b90a2c2741f8780f2
@email = foo@bar.com
@password = foobar

get login

GET https://192.168.99.100:9002/oauth2/auth/requests/login?login_challenge={{login_challenge}}

login

#POST {{9020_login}}
#Content-Type: application/x-www-form-urlencoded

#_csrf={{_csrf1}}
#&challenge={{login_challenge}}
#&email={{email}}
#&password={{password}}

accept login

PUT https://192.168.99.100:9002/oauth2/auth/requests/login/accept?login_challenge={{login_challenge}}
Content-Type: application/json

{
“subject”: “foo@bar.com”,
“remember”: false,
“remember_for”: 3600
}

@login_verifier = login_verifier=1025ccb8109047668715c8162459d6de

get conent

GET {{9001_auth}}{{login_verifier}}&{{client_id}}&{{redirect_url}}&{{scope}}&{{response_type}}&{{state}}&{{auth-tailpart}}

@consent_challenge = d23b6822d88842078a0d83677e8709a8
@_csrf2 = PLSPrz8R-GqmzKwgMtNus3LiX-p9Oh0QaLnQ

###GET {{9020_consent}}?consent_challenge={{consent_challenge}}

get conent scope

GET https://192.168.99.100:9002/oauth2/auth/requests/consent?consent_challenge={{consent_challenge}}

@submit = Allow access

accept conent scope

PUT https://192.168.99.100:9002/oauth2/auth/requests/consent/accept?consent_challenge={{consent_challenge}}
Content-Type: application/json

{
“grant_scope”: [“openid”, “photos.read”],
“session”: {
“access_token”: { “foo”: “bar” },
“id_token”: { “baz”: “bar” }
}
}

@consent_verifier = consent_verifier=ed04b20447c343338e9000b2db640f3c

get auth token

GET {{9001_auth}}{{consent_verifier}}&{{client_id}}&{{redirect_url}}&{{scope}}&{{response_type}}&{{state}}&{{auth-tailpart}}

http://192.168.99.100:4444/oauth2/auth?audience=&client_id=auth-code-client&consent_verifier=a643ae2e056543fabbd8d6f747e8a30c&max_age=0&nonce=chscixgzceuosfcocvvmjngj&prompt=&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=openid+offline&state=oplovvughuyzixqdvxnortrq

@token= xLPcJ3tobDqGUDxIVTxWt2p7w_odZSV22IAlUf5QPZU.YD6R_xKQ2ldCLbEV7mmc01E6ZLzemzdEC5H4-otTMPg

userinfo

GET https://openid.hydra:9001/userinfo
Authorization: Bearer {{token}}

introspect

POST https://openid.hydra:9002/oauth2/introspect
Content-Type: application/x-www-form-urlencoded

token={{token}}
&scope=openid+photos.read

GET https://openid.hydra:9002/oauth2/auth/sessions/consent?subject=foo@bar.com HTTP/1.1

PS:&scope=openid+photos.read can remove.  
  
PS:  
Here REST Client still return login page. go main server error log:  

### Post https://openid.hydra:9001/oauth2/token: x509: certificate signed by unknown authority

  
This is Go Server problem. See main.go Line:55-61 82-94 Fix this problem.  
  
  
  
  
\========== old ==========  
  
3、Now have problem is token user. When you run \*A, try to open web broswer. http://192.168.99.100:9010 then click "Authorize application" get error.  
Because "Authorize application" still is 127.0.0.1. No way to change. So copy Link change it.  
  

https://192.168.99.100:9001/oauth2/auth?audience=&client_id=auth-code-client&max_age=0&nonce=ylnybhabgcjllcxbfvhfjdfe&prompt=&redirect_uri=http%3A%2F%2F192.168.99.100%3A9010%2Fcallback&response_type=code&scope=openid+offline+photos.read&state=shqjytubxbrzqwtiskwwpfdp

Copy fix link to go. Fllow website.  
  
  
4、The Big problem is Allow access only get error. Can't know why.  
  
  

Rest Client || visual studio code
---------------------------------

Even by step to run. Still get error......