Go example

This code example shows how a relying party can integrate with GII using Go.

package main

import (

	// this example is using CoreOS OpenID Connect Client


func main() {

	giiServerAddress := os.Getenv("GII_SERVER_ADDRESS")
	if giiServerAddress == "" {
		giiServerAddress = "https://demo-api.gii.cloud"

	callbackURL := os.Getenv("RP_CALLBACK_URL")   // e.g. https://example.com/callback
	clientID := os.Getenv("RP_CLIENT_ID")         // e.g. example-id
	clientSecret := os.Getenv("RP_CLIENT_SECRET") // e.g. Sq8uN7aVQuD0

	ctx := context.Background()

	relyingPartyHTTP := http.NewServeMux()

	provider, err := oidc.NewProvider(ctx, giiServerAddress)
	if err != nil {
	oidcConfig := &oidc.Config{
		ClientID: clientID,
	verifier := provider.Verifier(oidcConfig)

	config := oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Endpoint:     provider.Endpoint(),
		RedirectURL:  callbackURL,
		Scopes:       []string{oidc.ScopeOpenID},

	// state should be random for each enduser browser session
	state := fmt.Sprintf("foobar-%v", rand.Int())

	relyingPartyHTTP.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			<!DOCTYPE html>
					<form action="login" method="get">
						<button type="submit">Login</button>

	// redirect the enduser to GIIs `authorization_endpoint` to initialize a login.
	relyingPartyHTTP.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, config.AuthCodeURL(state,
			// use UI created at /api/rp/ui endpoint with friendly ID 'example-ui'
			oauth2.SetAuthURLParam("ui_friendly", "example-ui"),
			// only show Swedish BankID
			oauth2.SetAuthURLParam("identity_provider", "bankid-se")), http.StatusFound)

	// this is the `callbackURL`. GII will navigate the enduser to this URL when the login is complete.
	relyingPartyHTTP.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Query().Get("state") != state {
			http.Error(w, "state did not match", http.StatusBadRequest)
		code := r.URL.Query().Get("code")
		if code == "" {
			http.Error(w, "Failed to get code", http.StatusUnauthorized)

		// call servers token-endpoint to get token with ID "code"
		oauth2Token, err := config.Exchange(ctx, code)
		if err != nil {
			http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusUnauthorized)
		rawIDToken, ok := oauth2Token.Extra("id_token").(string)
		if !ok {
			http.Error(w, "No id_token field in oauth2 token.", http.StatusUnauthorized)
		idToken, err := verifier.Verify(ctx, rawIDToken)
		if err != nil {
			http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusUnauthorized)

		// extract claims
		var claims struct {
			Subject  string `json:"sub"`
			Issuer   string `json:"issuer"`
			Audience string `json:"aud"`
			Nonce    string `json:"nonce"`

			SSN               string `json:"ssn"`
			SSNType           string `json:"ssn_type"`
			Email             string `json:"email"`
			EmailVerified     bool   `json:"email_verified"`
			Picture           string `json:"picture"`
			Name              string `json:"name"`
			PreferredUsername string `json:"preferred_username"`
			GivenName         string `json:"given_name"`
			FamilyName        string `json:"family_name"`
			Birthdate         string `json:"birthdate"`
			Gender            string `json:"gender"`
			PhoneNumber       string `json:"phone_number"`
		err = idToken.Claims(&claims)
		if err != nil {
			http.Error(w, "Failed to get claims: "+err.Error(), http.StatusUnauthorized)

			<!DOCTYPE html>
					<a href="/">Restart</a> <br/>
						Logged in as %s with SSN %s and birthdate %s
		`, claims.Name, claims.SSN, claims.Birthdate)))

	log.Printf("listening on http://localhost:1337/")
	err = http.ListenAndServe("localhost:1337", relyingPartyHTTP)
	if err != nil {
		log.Fatal("Relying Party server failed to start: " + err.Error())